• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import operator
7import os
8
9
10# TODO: This is a quick workaround; some of our arm devices so far only
11# support the HDMI EDIDs and the DP one at 1680x1050. A more proper
12# solution is to build a database of supported resolutions and pixel
13# clocks for each model and check if the EDID is in the supported list.
14def is_edid_supported(host, width, height):
15    """Check whether the EDID is supported by DUT
16
17    @param host: A CrosHost object.
18    @param width: The screen width
19    @param height: The screen height
20
21    @return: True if the check passes; False otherwise.
22    """
23    # TODO: Support client test that the host is not a CrosHost.
24    platform = host.get_platform()
25    prefix = platform.lower().split('_')[0]
26    if prefix in ('snow', 'spring', 'skate', 'peach', 'veyron'):
27        if (width, height) in [(1280, 800), (1440, 900), (1600, 900),
28                               (3840, 2160)]:
29            return False
30    return True
31
32
33class Edid(object):
34    """Edid is an abstraction of EDID (Extended Display Identification Data).
35
36    It provides methods to get the properties, manipulate the structure,
37    import from a file, export to a file, etc.
38
39    """
40
41    BLOCK_SIZE = 128
42
43
44    def __init__(self, data, skip_verify=False):
45        """Construct an Edid.
46
47        @param data: A byte-array of EDID data.
48        @param skip_verify: True to skip the correctness check.
49        """
50        if not Edid.verify(data) and not skip_verify:
51            raise ValueError('Not a valid EDID.')
52        self.data = data
53
54
55    @staticmethod
56    def verify(data):
57        """Verify the correctness of EDID.
58
59        @param data: A byte-array of EDID data.
60
61        @return True if the EDID is correct; False otherwise.
62        """
63        data_len = len(data)
64        if data_len % Edid.BLOCK_SIZE != 0:
65            logging.debug('EDID has an invalid length: %d', data_len)
66            return False
67
68        for start in xrange(0, data_len, Edid.BLOCK_SIZE):
69            # Each block (128-byte) has a checksum at the last byte.
70            checksum = reduce(operator.add,
71                              map(ord, data[start:start+Edid.BLOCK_SIZE]))
72            if checksum % 256 != 0:
73                logging.debug('Wrong checksum in the block %d of EDID',
74                              start / Edid.BLOCK_SIZE)
75                return False
76
77        return True
78
79
80    @classmethod
81    def from_file(cls, filename, skip_verify=False):
82        """Construct an Edid from a file.
83
84        @param filename: A string of filename.
85        @param skip_verify: True to skip the correctness check.
86        """
87        if not os.path.exists(filename):
88            raise ValueError('EDID file %r does not exist' % filename)
89
90        if filename.upper().endswith('.TXT'):
91            # Convert the EDID text format, returning from xrandr.
92            data = reduce(operator.add,
93                          map(lambda s: s.strip().decode('hex'),
94                              open(filename).readlines()))
95        else:
96            data = open(filename).read()
97        return cls(data, skip_verify)
98
99
100    def to_file(self, filename):
101        """Export the EDID to a file.
102
103        @param filename: A string of filename.
104        """
105        with open(filename, 'w+') as f:
106            f.write(self.data)
107
108
109# A constant object to represent no EDID.
110NO_EDID = Edid('', skip_verify=True)
111