Tizen 2.1 base
[framework/uifw/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 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30
31 /* TODO:
32  * - see other TODO's within this file.
33  */
34
35 #define ECORE_X_RANDR_EDID_VERSION_10                                   ((1 << 8) | 0)
36 #define ECORE_X_RANDR_EDID_VERSION_11                                   ((1 << 8) | 1)
37 #define ECORE_X_RANDR_EDID_VERSION_12                                   ((1 << 8) | 2)
38 #define ECORE_X_RANDR_EDID_VERSION_13                                   ((1 << 8) | 3)
39 #define ECORE_X_RANDR_EDID_VERSION_14                                   ((1 << 8) | 4)
40
41 #define _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER                         0x08
42 #define _ECORE_X_RANDR_EDID_OFFSET_TYPE                                 0x14
43 #define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR                        0x12
44 #define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR                        0x13
45 #define _ECORE_X_RANDR_EDID_OFFSET_DPMS                                 0x18
46 #define _ECORE_X_RANDR_EDID_OFFSET_COLORSPACE                           0x18
47 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK                     0x36
48 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE                3
49 #define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT             5
50 #define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED               15
51 #define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO                         14
52
53 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL                                0x80
54 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL_INTERFACE                      0x0f
55 #define _ECORE_X_RANDR_EDID_MASK_DIGITAL_TMDS_DFP_10                    0x01
56 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS                  0x18
57 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444          0x10
58 #define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422          0x08
59 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED                 0xe0
60 #define _ECORE_X_RANDR_EDID_MASK_DPMS                                   0xE0
61 #define _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY                           0x80
62 #define _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND                           0x40
63 #define _ECORE_X_RANDR_EDID_MASK_DPMS_OFF                               0x20
64 #define _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE                         0x0f
65 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3                       0x80
66 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9                      0x40
67 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10                     0x20
68 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4                       0x10
69 #define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9                      0x08
70
71 #define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13
72
73 typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred {
74    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00,
75    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01,
76    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02,
77    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03,
78    ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04
79 } Ecore_X_Randr_Edid_Aspect_Ratio_Preferred;
80
81 /* Some convenience loops */
82 #define _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, extension_block_iter) \
83   for (extension_block_iter = edid; extension_block_iter < (edid + edid_length); extension_block_iter += 128)
84
85 #define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \
86   _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, cea_block_iter) \
87   if (cea_block_iter[0] == 0x02)
88
89 /* The following macro is to be used with caution as it inherits another loop.
90  * Therefore using a 'break;' statement will lead to continuation in the
91  * inherent 'Extension block'-loop.
92  */
93 #define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_DETAILED_BLOCK(edid, edid_length, cea_block_iter, detailed_block_iter)                              \
94   _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter)                                                                  \
95   for (detailed_block_iter = cea_block_iter + cea_block_iter[2]; detailed_block_iter + 18 < cea_block_iter + 127; detailed_block_iter += 18) \
96     if (detailed_block_iter[0])
97
98 #define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
99   for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3 * 18)); block += 18)
100
101 #define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \
102   _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block)                 \
103   if ((block[0] == 0) && (block[1] == 0))
104
105 EAPI Eina_Bool
106 ecore_x_randr_edid_has_valid_header(unsigned char *edid,
107                                     unsigned long edid_length)
108 {
109    const unsigned char header[] =
110    { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
111    if (!edid) return EINA_FALSE;
112    if (edid_length < 8) return EINA_FALSE;
113    if (!memcmp(edid, header, 8)) return EINA_TRUE;
114    return EINA_FALSE;
115 }
116
117 EAPI int
118 ecore_x_randr_edid_version_get(unsigned char *edid,
119                                unsigned long edid_length)
120 {
121    if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) &&
122        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
123      return (edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) |
124             edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR];
125    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
126 }
127
128 EAPI int
129 ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid,
130                                           unsigned long edid_length)
131 {
132    if ((edid_length > 0x0b) &&
133        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
134      return (int)(edid[0x0a] + (edid[0x0b] << 8));
135    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
136 }
137
138 EAPI int
139 ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid,
140                                                   unsigned long edid_length)
141 {
142    if ((edid_length > 0x0f) &&
143        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
144      return (int)(edid[0x0c] + (edid[0x0d] << 8) +
145                   (edid[0x0e] << 16) + (edid[0x0f] << 24));
146    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
147 }
148
149 EAPI char *
150 ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid,
151                                          unsigned long edid_length)
152 {
153    if ((edid_length > (_ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER + 1)) &&
154        (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
155      {
156         unsigned char *x;
157         char *name;
158
159         x = (edid + _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER);
160         name = malloc(sizeof(char) * 4);
161         if (!name) return NULL;
162         name[0] = ((x[0] & 0x7c) >> 2) + '@';
163         name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
164         name[2] = (x[1] & 0x1f) + '@';
165         name[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] = 0;
166         return name;
167      }
168    return NULL;
169 }
170
171 EAPI char *
172 ecore_x_randr_edid_display_name_get(unsigned char *edid,
173                                     unsigned long edid_length)
174 {
175    unsigned char *block = NULL;
176    int version = ecore_x_randr_edid_version_get(edid, edid_length);
177
178    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
179    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
180    {
181       if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc)
182         {
183            char *name, *p;
184            const char *edid_name;
185
186            edid_name = (const char *)block + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
187            name = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
188            if (!name) return NULL;
189            strncpy(name, edid_name, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
190            name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
191            for (p = name; *p; p++)
192              {
193                 if ((*p < ' ') || (*p > '~')) *p = 0;
194              }
195            return name;
196         }
197    }
198    return NULL;
199 }
200
201 EAPI Ecore_X_Randr_Edid_Aspect_Ratio
202 ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid,
203                                                       unsigned long edid_length)
204 {
205    unsigned char *block = NULL;
206    int version = ecore_x_randr_edid_version_get(edid, edid_length);
207
208    if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
209    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
210    {
211       if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
212           (block[10] == 0x04))
213         {
214            Ecore_X_Randr_Edid_Aspect_Ratio_Preferred preferred_ratio =
215              (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)
216              ((block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED] &
217                _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED) >> 5);
218            switch (preferred_ratio)
219              {
220               case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3:
221                 return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
222
223               case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9:
224                 return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
225
226               case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10:
227                 return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
228
229               case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4:
230                 return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
231
232               case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9:
233                 return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
234
235               default:
236                 return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
237              }
238         }
239    }
240    return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
241 }
242
243 EAPI Ecore_X_Randr_Edid_Aspect_Ratio
244 ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid,
245                                              unsigned long edid_length)
246 {
247    Ecore_X_Randr_Edid_Aspect_Ratio ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
248    unsigned char *block = NULL;
249    int version = ecore_x_randr_edid_version_get(edid, edid_length);
250
251    if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
252    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
253    {
254       if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
255           (block[10] == 0x04))
256         {
257            if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3)
258              ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
259            if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9)
260              ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
261            if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10)
262              ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
263            if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4)
264              ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
265            if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9)
266              ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
267         }
268    }
269    return ret;
270 }
271
272 EAPI char *
273 ecore_x_randr_edid_display_ascii_get(unsigned char *edid,
274                                      unsigned long edid_length)
275 {
276    unsigned char *block = NULL;
277    int version = ecore_x_randr_edid_version_get(edid, edid_length);
278
279    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
280    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
281    {
282       if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfe)
283         {
284            char *ascii, *p;
285            const char *edid_ascii = (const char *)block +
286              _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
287            /*
288             * TODO: Two of these in a row, in the third and fourth slots,
289             * seems to be specified by SPWG: http://www.spwg.org/
290             */
291            ascii = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
292            if (!ascii) return NULL;
293            strncpy(ascii, edid_ascii, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
294            ascii[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
295            for (p = ascii; *p; p++)
296              {
297                 if ((*p < ' ') || (*p > '~')) *p = 0;
298              }
299            return ascii;
300         }
301    }
302    return NULL;
303 }
304
305 EAPI char *
306 ecore_x_randr_edid_display_serial_get(unsigned char *edid,
307                                       unsigned long edid_length)
308 {
309    unsigned char *block = NULL;
310    int version = ecore_x_randr_edid_version_get(edid, edid_length);
311
312    if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
313    _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
314    {
315       if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xff)
316         {
317            char *serial, *p;
318            const char *edid_serial = (const char *)block +
319              _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
320            /*
321             * TODO: Two of these in a row, in the third and fourth slots,
322             * seems to be specified by SPWG: http://www.spwg.org/
323             */
324            serial = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
325            if (!serial) return NULL;
326            strncpy(serial, edid_serial, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
327            serial[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
328            for (p = serial; *p; p++)
329              {
330                 if ((*p < ' ') || (*p > '~')) *p = 0;
331              }
332            return serial;
333         }
334    }
335    return NULL;
336 }
337
338 EAPI Eina_Bool
339 ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid,
340                                            unsigned long edid_length)
341 {
342    unsigned char *cea_block_iter = NULL;
343    char sum = 0;
344    int i;
345    int version = ecore_x_randr_edid_version_get(edid, edid_length);
346
347    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
348    if (edid_length < 128) return EINA_FALSE;
349
350    /* Check the EDID block itself */
351    for (i = 0; i < 128; i++)
352      sum += edid[i];
353    if (sum) return EINA_FALSE;
354
355    /* Check the cea extension blocks */
356    _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter)
357    {
358       for (i = 0, sum = 0; i < 128; i++)
359         sum += cea_block_iter[i];
360    }
361    if (sum) return EINA_FALSE;
362    return EINA_TRUE;
363 }
364
365 EAPI Eina_Bool
366 ecore_x_randr_edid_dpms_available_get(unsigned char *edid,
367                                       unsigned long edid_length)
368 {
369    int version = ecore_x_randr_edid_version_get(edid, edid_length);
370
371    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
372    return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
373              _ECORE_X_RANDR_EDID_MASK_DPMS);
374 }
375
376 EAPI Eina_Bool
377 ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid,
378                                               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_STANDBY);
386    return EINA_FALSE;
387 }
388
389 EAPI Eina_Bool
390 ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid,
391                                               unsigned long edid_length)
392 {
393    int version = ecore_x_randr_edid_version_get(edid, edid_length);
394
395    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
396    if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
397      return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
398                _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND);
399    return EINA_FALSE;
400 }
401
402 EAPI Eina_Bool
403 ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid,
404                                           unsigned long edid_length)
405 {
406    int version = ecore_x_randr_edid_version_get(edid, edid_length);
407
408    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
409    if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
410      return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
411                _ECORE_X_RANDR_EDID_MASK_DPMS_OFF);
412    return EINA_FALSE;
413 }
414
415 EAPI Eina_Bool
416 ecore_x_randr_edid_display_type_digital_get(unsigned char *edid,
417                                             unsigned long edid_length)
418 {
419    int version = ecore_x_randr_edid_version_get(edid, edid_length);
420
421    if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
422    return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
423              _ECORE_X_RANDR_EDID_MASK_DIGITAL);
424 }
425
426 EAPI Ecore_X_Randr_Edid_Display_Colorscheme
427 ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid,
428                                            unsigned long edid_length)
429 {
430    Ecore_X_Randr_Edid_Display_Colorscheme colorscheme = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
431    int version = ecore_x_randr_edid_version_get(edid, edid_length);
432
433    if (version < ECORE_X_RANDR_EDID_VERSION_13) return colorscheme;
434    if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length))
435      {
436         colorscheme = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4;
437         if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
438             _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444)
439           colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4;
440         if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
441             _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422)
442           colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2;
443      }
444    else
445      colorscheme = edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS;
446    return colorscheme;
447 }
448
449 EAPI Ecore_X_Randr_Edid_Display_Interface_Type
450 ecore_x_randr_edid_display_interface_type_get(unsigned char *edid,
451                                               unsigned long edid_length)
452 {
453    Ecore_X_Randr_Edid_Display_Interface_Type type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
454    int version = ecore_x_randr_edid_version_get(edid, edid_length);
455
456    if (version < ECORE_X_RANDR_EDID_VERSION_13) return type;
457    type = edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
458      _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE;
459    if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
460      type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
461    return type;
462 }
463