svn update: 60286 (latest:60286)
[profile/ivi/ecore.git] / src / lib / ecore_x / xlib / ecore_x_randr_12_edid.c
1 /*
2  * Copyright 2006-2009 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 /* Original Author: Adam Jackson <ajax@nwnk.net> */
23 /* Heavily modified by: Leif Middelschulte <leif.middelschulte@gmail.com> */
24
25 #include "Ecore_X.h"
26
27 /* TODO:
28  * - see other TODO's within this file.
29  */
30
31 #define ECORE_X_RANDR_EDID_VERSION_10 ((1 << 8) | 0)
32 #define ECORE_X_RANDR_EDID_VERSION_11 ((1 << 8) | 1)
33 #define ECORE_X_RANDR_EDID_VERSION_12 ((1 << 8) | 2)
34 #define ECORE_X_RANDR_EDID_VERSION_13 ((1 << 8) | 3)
35 #define ECORE_X_RANDR_EDID_VERSION_14 ((1 << 8) | 4)
36
37 #define _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER 0x08
38 #define _ECORE_X_RANDR_EDID_OFFSET_TYPE 0x14
39 #define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR 0x12
40 #define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR 0x13
41 #define _ECORE_X_RANDR_EDID_OFFSET_DPMS 0x18
42 #define _ECORE_X_RANDR_EDID_OFFSET_COLORSPACE 0x18
43 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK 0x36
44 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE 3
45 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT 5
46 #define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED 15
47 #define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO 14
48
49 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL 0x80
50 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL_INTERFACE 0x0f
51 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL_TMDS_DFP_10 0x01
52 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS 0x18
53 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444 0x10
54 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422 0x08
55 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED 0xe0
56 #define _ECORE_X_RANDR_EDID_MASK_DPMS 0xE0
57 #define _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY 0x80
58 #define _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND 0x40
59 #define _ECORE_X_RANDR_EDID_MASK_DPMS_OFF 0x20
60 #define _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE 0x0f
61 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3 0x80
62 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9 0x40
63 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10 0x20
64 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4 0x10
65 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9 0x08
66
67 #define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13
68
69 typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred {
70    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00,
71       ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01,
72       ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02,
73       ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03,
74       ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04
75 } Ecore_X_Randr_Edid_Aspect_Ratio_Preferred;
76
77 /* Some convenience loops */
78 #define _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, extension_block_iter) \
79    for (extension_block_iter = edid; extension_block_iter < (edid + edid_length); extension_block_iter += 128)
80
81 #define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \
82    _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, cea_block_iter) \
83          if (cea_block_iter[0] == 0x02)
84
85 /* The following macro is to be used with caution as it inherits another loop.
86  * Therefore using a 'break;' statement will lead to continuation in the
87  * inherent 'Extension block'-loop.
88  */
89 #define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_DETAILED_BLOCK(edid, edid_length, cea_block_iter, detailed_block_iter) \
90    _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \
91          for (detailed_block_iter = cea_block_iter + cea_block_iter[2]; detailed_block_iter + 18 < cea_block_iter + 127; detailed_block_iter += 18) \
92             if (detailed_block_iter[0])
93
94 #define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
95    for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3*18)); block += 18)
96
97 #define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \
98    _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
99          if ((block[0] == 0) && (block[1] == 0))
100
101 EAPI Eina_Bool
102 ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length)
103 {
104    const unsigned char header[] =
105      { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
106    if (!edid) return EINA_FALSE;
107    if (edid_length < 8) return EINA_FALSE;
108    if (!memcmp(edid, header, 8)) return EINA_TRUE;
109    return EINA_FALSE;
110 }
111
112 EAPI int
113 ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length)
114 {
115    if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) &&
116        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
117       return ((edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) |
118               edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR]);
119    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
120 }
121
122 EAPI int
123 ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length)
124 {
125    if ((edid_length > 0x0b) &&
126        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
127       return (int)(edid[0x0a] + (edid[0x0b] << 8));
128    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
129 }
130
131 EAPI int
132 ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length)
133 {
134    if ((edid_length > 0x0f) &&
135        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
136       return (int)(edid[0x0c] + (edid[0x0d] << 8) +
137                    (edid[0x0e] << 16) + (edid[0x0f] << 24));
138    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
139 }
140
141 EAPI char *
142 ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length)
143 {
144    if ((edid_length > (_ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER + 1)) &&
145        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
146      {
147         unsigned char *x;
148         char *name;
149
150         x = (edid + _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER);
151         name = malloc(sizeof(char) * 4);
152         if (!name) return NULL;
153         name[0] = ((x[0] & 0x7c) >> 2) + '@';
154         name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
155         name[2] = (x[1] & 0x1f) + '@';
156         name[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] = 0;
157         return name;
158      }
159    return NULL;
160 }
161
162 EAPI char *
163 ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length)
164 {
165    unsigned char *block = NULL;
166    int version = ecore_x_randr_edid_version_get(edid, edid_length);
167
168    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
169    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
170      {
171         if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc)
172           {
173              char *name, *p;
174              const char *edid_name;
175
176              edid_name = (const char *)block + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
177              name = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
178              if (!name) return NULL;
179              strncpy(name, edid_name, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
180              name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
181              for (p = name; *p; p++)
182                {
183                   if ((*p < ' ') || (*p > '~')) *p = 0;
184                }
185              return name;
186           }
187      }
188    return NULL;
189 }
190
191 EAPI Ecore_X_Randr_Edid_Aspect_Ratio
192 ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length)
193 {
194    unsigned char *block = NULL;
195    int version = ecore_x_randr_edid_version_get(edid, edid_length);
196
197    if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
198    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
199      {
200         if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
201             (block[10] == 0x04))
202           {
203              Ecore_X_Randr_Edid_Aspect_Ratio_Preferred preferred_ratio =
204                 (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)
205                 ((block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED] &
206                   _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED) >> 5);
207              switch (preferred_ratio)
208                {
209                 case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3:
210                   return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
211                 case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9:
212                   return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
213                 case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10:
214                   return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
215                 case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4:
216                   return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
217                 case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9:
218                   return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
219                 default:
220                   return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
221                }
222           }
223      }
224    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
225 }
226
227 EAPI Ecore_X_Randr_Edid_Aspect_Ratio
228 ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length)
229 {
230    Ecore_X_Randr_Edid_Aspect_Ratio ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
231    unsigned char *block = NULL;
232    int version = ecore_x_randr_edid_version_get(edid, edid_length);
233
234    if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
235    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
236      {
237         if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
238             (block[10] == 0x04))
239           {
240              if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3)
241                 ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
242              if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9)
243                 ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
244              if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10)
245                 ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
246              if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4)
247                 ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
248              if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9)
249                 ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
250           }
251      }
252    return ret;
253 }
254
255 EAPI char *
256 ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length)
257 {
258    unsigned char *block = NULL;
259    int version = ecore_x_randr_edid_version_get(edid, edid_length);
260
261    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
262    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
263      {
264         if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfe)
265           {
266              char *ascii, *p;
267              const char *edid_ascii = (const char*)block +
268                 _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
269              /*
270               * TODO: Two of these in a row, in the third and fourth slots,
271               * seems to be specified by SPWG: http://www.spwg.org/
272               */
273              ascii = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
274              if (!ascii) return NULL;
275              strncpy(ascii, edid_ascii, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
276              ascii[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
277              for (p = ascii; *p; p++)
278                {
279                   if ((*p < ' ') || (*p > '~')) *p = 0;
280                }
281              return ascii;
282           }
283      }
284    return NULL;
285 }
286
287 EAPI char *
288 ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length)
289 {
290    unsigned char *block = NULL;
291    int version = ecore_x_randr_edid_version_get(edid, edid_length);
292
293    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
294    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
295      {
296         if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xff)
297           {
298              char *serial, *p;
299              const char *edid_serial = (const char*)block +
300                 _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
301              /*
302               * TODO: Two of these in a row, in the third and fourth slots,
303               * seems to be specified by SPWG: http://www.spwg.org/
304               */
305              serial = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
306              if (!serial) return NULL;
307              strncpy(serial, edid_serial, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
308              serial[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
309              for (p = serial; *p; p++)
310                {
311                   if ((*p < ' ') || (*p > '~')) *p = 0;
312                }
313              return serial;
314           }
315      }
316    return NULL;
317 }
318
319 EAPI Eina_Bool
320 ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length)
321 {
322    unsigned char *cea_block_iter = NULL;
323    char sum = 0;
324    int i;
325    int version = ecore_x_randr_edid_version_get(edid, edid_length);
326
327    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
328    if (edid_length < 128) return EINA_FALSE;
329
330    /* Check the EDID block itself */
331    for (i = 0; i < 128; i++) sum += edid[i];
332    if (sum) return EINA_FALSE;
333
334    /* Check the cea extension blocks */
335    _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter)
336      {
337         for (i = 0, sum = 0; i < 128; i++) sum += cea_block_iter[i];
338      }
339    if (sum) return EINA_FALSE;
340    return EINA_TRUE;
341 }
342
343 EAPI Eina_Bool
344 ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length)
345 {
346    int version = ecore_x_randr_edid_version_get(edid, edid_length);
347
348    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
349    return (!!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
350               _ECORE_X_RANDR_EDID_MASK_DPMS));
351 }
352
353 EAPI Eina_Bool
354 ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length)
355 {
356    int version = ecore_x_randr_edid_version_get(edid, edid_length);
357
358    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
359    if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
360       return (!!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
361                  _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY));
362    return EINA_FALSE;
363 }
364
365 EAPI Eina_Bool
366 ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length)
367 {
368    int version = ecore_x_randr_edid_version_get(edid, edid_length);
369
370    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
371    if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
372       return (!!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
373                  _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND));
374    return EINA_FALSE;
375 }
376
377 EAPI Eina_Bool
378 ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length)
379 {
380    int version = ecore_x_randr_edid_version_get(edid, edid_length);
381
382    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
383    if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
384       return (!!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
385                  _ECORE_X_RANDR_EDID_MASK_DPMS_OFF));
386    return EINA_FALSE;
387 }
388
389 EAPI Eina_Bool
390 ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length)
391 {
392    int version = ecore_x_randr_edid_version_get(edid, edid_length);
393
394    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
395    return (!!(edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
396               _ECORE_X_RANDR_EDID_MASK_DIGITAL));
397 }
398
399 EAPI Ecore_X_Randr_Edid_Display_Colorscheme
400 ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length)
401 {
402    Ecore_X_Randr_Edid_Display_Colorscheme colorscheme = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
403    int version = ecore_x_randr_edid_version_get(edid, edid_length);
404
405    if (version < ECORE_X_RANDR_EDID_VERSION_13) return colorscheme;
406    if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length))
407      {
408         colorscheme = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4;
409         if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
410             _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444)
411            colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4;
412         if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
413             _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422)
414            colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2;
415      }
416    else
417       colorscheme = edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS;
418    return colorscheme;
419 }
420
421 EAPI Ecore_X_Randr_Edid_Display_Interface_Type
422 ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length)
423 {
424    Ecore_X_Randr_Edid_Display_Interface_Type type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
425    int version = ecore_x_randr_edid_version_get(edid, edid_length);
426
427    if (version < ECORE_X_RANDR_EDID_VERSION_13) return type;
428    type = edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
429       _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE;
430    if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
431       type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
432    return type;
433 }