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 if platform in ('snow', 'spring', 'skate', 'peach_pi', 'veyron_jerry'): 26 if (width, height) in [(1280, 800), (1440, 900), (1600, 900), 27 (3840, 2160)]: 28 return False 29 if platform in ('kahlee', 'grunt'): 30 if (width, height) in [(3840, 2160)]: 31 return False 32 return True 33 34 35class Edid(object): 36 """Edid is an abstraction of EDID (Extended Display Identification Data). 37 38 It provides methods to get the properties, manipulate the structure, 39 import from a file, export to a file, etc. 40 41 """ 42 43 BLOCK_SIZE = 128 44 45 46 def __init__(self, data, skip_verify=False): 47 """Construct an Edid. 48 49 @param data: A byte-array of EDID data. 50 @param skip_verify: True to skip the correctness check. 51 """ 52 if not Edid.verify(data) and not skip_verify: 53 raise ValueError('Not a valid EDID.') 54 self.data = data 55 56 57 @staticmethod 58 def verify(data): 59 """Verify the correctness of EDID. 60 61 @param data: A byte-array of EDID data. 62 63 @return True if the EDID is correct; False otherwise. 64 """ 65 data_len = len(data) 66 if data_len % Edid.BLOCK_SIZE != 0: 67 logging.debug('EDID has an invalid length: %d', data_len) 68 return False 69 70 for start in xrange(0, data_len, Edid.BLOCK_SIZE): 71 # Each block (128-byte) has a checksum at the last byte. 72 checksum = reduce(operator.add, 73 map(ord, data[start:start+Edid.BLOCK_SIZE])) 74 if checksum % 256 != 0: 75 logging.debug('Wrong checksum in the block %d of EDID', 76 start / Edid.BLOCK_SIZE) 77 return False 78 79 return True 80 81 82 @classmethod 83 def from_file(cls, filename, skip_verify=False): 84 """Construct an Edid from a file. 85 86 @param filename: A string of filename. 87 @param skip_verify: True to skip the correctness check. 88 """ 89 if not os.path.exists(filename): 90 raise ValueError('EDID file %r does not exist' % filename) 91 92 if filename.upper().endswith('.TXT'): 93 # Convert the EDID text format, returning from xrandr. 94 data = reduce(operator.add, 95 map(lambda s: s.strip().decode('hex'), 96 open(filename).readlines())) 97 else: 98 data = open(filename).read() 99 return cls(data, skip_verify) 100 101 102 def to_file(self, filename): 103 """Export the EDID to a file. 104 105 @param filename: A string of filename. 106 """ 107 with open(filename, 'w+') as f: 108 f.write(self.data) 109 110 111# A constant object to represent no EDID. 112NO_EDID = Edid('', skip_verify=True) 113