| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Checks EDID for errors, which could indicate invalid or faulty EDID. |
| |
| If errors are found, returns error.Error objects that store information about |
| each error's location, message, expected data, and what data is found. |
| """ |
| |
| import descriptor |
| import error |
| import extensions |
| import standard_timings |
| |
| |
| def _LengthError(e): |
| """Checks if the length of the EDID is a multiple of 128. |
| |
| Args: |
| e: The list form of the EDID to be checked. |
| |
| Returns: |
| A list of error.Error objects, or None. |
| """ |
| if not len(e) % 128: |
| return None |
| else: |
| return [error.Error('Overall EDID', 'Invalid length', 'Length % 128 = 0', |
| 'Length %% 128 = %d' % (len(e) % 128))] |
| |
| |
| def _HeaderError(e): |
| """Checks if header (bytes 0-7) is set up properly. |
| |
| Header should be 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00. |
| |
| Args: |
| e: The list form of the EDID to be checked. |
| |
| Returns: |
| A list of error.Error objects, or None. |
| """ |
| magic_header = [ |
| 0x00, |
| 0xFF, |
| 0xFF, |
| 0xFF, |
| 0xFF, |
| 0xFF, |
| 0xFF, |
| 0x00 |
| ] |
| |
| header = '%02X%02X ' * 4 % tuple(e[0:8]) |
| |
| if e[0:8] == magic_header: |
| return None |
| else: |
| return [error.Error('Bytes 0-7', 'Incorrect EDID header', |
| '00FF FFFF FFFF FF00', header)] |
| |
| return None |
| |
| |
| def _ChecksumError(e): |
| """Checks if checksum is valid. |
| |
| Checksum for each 128-byte block should be divisible by 256. |
| |
| Args: |
| e: The list form of the EDID to be checked. |
| |
| Returns: |
| None, if no error, or a list of error.Error objects. |
| """ |
| cs_errors = [] |
| |
| for x in xrange(0, len(e), 128): |
| |
| my_sum = sum(e[x : x + 128]) |
| if my_sum % 256: |
| block_id = x / 128 |
| my_err = error.Error('Block %d' % block_id, 'Checksum error', |
| 'Sum % 256 = 0', 'Sum %% 256 = %d' % (my_sum % 256)) |
| cs_errors.append(my_err) |
| |
| return cs_errors |
| |
| |
| def _DescriptorErrors(edid, version): |
| """Checks the descriptor blocks for errors. |
| |
| Args: |
| edid: The list form of the EDID to be checked. |
| version: The string indicating the version of the EDID. |
| |
| Returns: |
| A list of error.Error objects. |
| """ |
| base = 54 # Descriptor blocks start at byte 54 in base EDID |
| |
| errors = [] |
| |
| for x in xrange(0, 4): |
| |
| desc = descriptor.GetDescriptor(edid, base + (x * 18), version) |
| |
| desc_errors = desc.CheckErrors(x + 1) |
| |
| if desc_errors: |
| errors.extend(desc_errors) |
| |
| return errors |
| |
| |
| def _BaseStErrors(edid, version): |
| """Checks the standard timing section for errors. |
| |
| Args: |
| edid: The list form of the EDID to be checked. |
| version: A string indicating the EDID's version. |
| |
| Returns: |
| A list of error.Error objects. |
| """ |
| base = 38 |
| |
| errors = [] |
| |
| for x in xrange(0, 8): |
| st = standard_timings.GetStandardTiming(edid, base + (x * 2), version) |
| if st: |
| err = st.CheckErrors(x + 1) |
| if err: |
| errors.extend(err) |
| |
| return errors |
| |
| |
| def _ExtensionErrors(edid, version): |
| """Checks all extensions for errors. |
| |
| Args: |
| edid: The EDID being checked. |
| version: A string indicating the EDID's version. |
| |
| Returns: |
| A list of error.Error objects. |
| """ |
| num_ext = edid[0x7E] |
| |
| errors = [] |
| |
| if (num_ext + 1) != (len(edid) / 128): |
| errors.append(error.Error('Extensions', 'Extension count does not match ' |
| 'EDID length', '%d extensions' % num_ext, |
| '%d extensions' % ((len(edid) / 128) - 1))) |
| |
| for x in xrange(1, num_ext + 1): |
| ext = extensions.GetExtension(edid, x, version) |
| |
| err = ext.CheckErrors(x) |
| if err: |
| errors.extend(err) |
| |
| return errors |
| |
| |
| def _WeekError(edid): |
| """Checks if the manufacturer week is in the proper range of 1-54. |
| |
| Args: |
| edid: The list form of the EDID being checked. |
| |
| Returns: |
| An error.Error object, if there's an error. |
| """ |
| if edid[0x10] > 54 and edid[0x10] != 255: |
| return [error.Error('Manufacturer/Vendor section- byte 0x10', 'Invalid week' |
| ' value', 'Week in range 1-54', 'Week %d' % edid[0x10])] |
| |
| |
| def GetErrors(edid, version): |
| """Checks EDID for all potential errors. |
| |
| Args: |
| edid: The list form of the EDID being checked. |
| version: The string representing the version of the EDID. |
| |
| Returns: |
| A list of error.Error objects. |
| """ |
| errors = [] |
| |
| # Check for various errors, and add them to error list |
| |
| error_check_functions = [ |
| _HeaderError(edid), |
| _ChecksumError(edid), |
| _LengthError(edid), |
| _WeekError(edid), |
| _DescriptorErrors(edid, version), |
| _BaseStErrors(edid, version), |
| _ExtensionErrors(edid, version) |
| ] |
| |
| for err in error_check_functions: |
| if err: |
| errors.extend(err) |
| |
| return errors |
| |
| |