blob: 235f775b9102af3e00e8a49380acad754f4389db [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2011 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.
"""EDID Parser (light-weight parse-edid replacement)
This module provides simple parsing of EDID (
http://en.wikipedia.org/wiki/Extended_display_identification_data ) because the
full-feature parser (parse-edid) has too much dependency.
TODO(hungte) Use parse-edid if available.
"""
import sys
# EDID Constants
EDID_VERSION = 0x01
EDID_MAGIC = '\x00\xff\xff\xff\xff\xff\xff\x00'
EDID_MAGIC_OFFSET = 0
EDID_MANUFACTURER_ID_OFFSET = 8
EDID_PRODUCT_ID_OFFSET = 10
EDID_VERSION_OFFSET = 18
EDID_REVISION_OFFSET = 19
EDID_PIXEL_CLOCK_OFFSET = 54
EDID_HORIZONTAL_OFFSET = 56
EDID_HORIZONTAL_HIGH_OFFSET = 58
EDID_VERTICAL_OFFSET = 59
EDID_VERTICAL_HIGH_OFFSET = 61
EDID_CHECKSUM_OFFSET = 127
EDID_MINIMAL_SIZE = 128
EDID_MANUFACTURER_ID_BITS = 5
EDID_MANUFACTURER_ID = 'manufactuer_id'
EDID_PRODUCT_ID = 'product_id'
EDID_WIDTH = 'width'
EDID_HEIGHT = 'height'
def parse_edid(blob):
"""Parses a in-memory EDID blob.
Args:
blob: a binary blob with encoded EDID.
Returns:
A dictionary of extracted information, or raise ValueError if the blob is
not a valid EDID record.
"""
def read_short(offset):
return ((ord(blob[offset]) << 8) | ord(blob[offset + 1]))
data = {}
# Check size, magic, and version
if len(blob) < EDID_MINIMAL_SIZE:
raise ValueError("Length too small")
if (blob[EDID_MAGIC_OFFSET:(EDID_MAGIC_OFFSET + len(EDID_MAGIC))] !=
EDID_MAGIC):
raise ValueError("Incorrect header")
if ord(blob[EDID_VERSION_OFFSET]) != EDID_VERSION:
raise ValueError("Unsupported EDID version")
# Verify checksum
if sum([ord(char) for char in blob[:EDID_CHECKSUM_OFFSET+1]]) % 0x100 != 0:
raise ValueError("Checksum error.")
# Currently we don't support EDID not using pixel clock
pixel_clock = read_short(EDID_PIXEL_CLOCK_OFFSET)
if not pixel_clock:
raise ValueError("Non-pixel clock format is not supported yet")
# Extract manufactuer
vendor_name = ''
vendor_code = read_short(EDID_MANUFACTURER_ID_OFFSET)
# vendor_code: [0 | char1 | char2 | char3]
for i in range(2, -1, -1):
vendor_char = (vendor_code >> (i * EDID_MANUFACTURER_ID_BITS)) & 0x1F
vendor_char = chr(vendor_char + ord('@'))
vendor_name += vendor_char
data[EDID_MANUFACTURER_ID] = vendor_name
product_id = read_short(EDID_PRODUCT_ID_OFFSET)
data[EDID_PRODUCT_ID] = product_id
width = (ord(blob[EDID_HORIZONTAL_OFFSET]) |
((ord(blob[EDID_HORIZONTAL_HIGH_OFFSET]) >> 4) << 8))
height = (ord(blob[EDID_VERTICAL_OFFSET]) |
((ord(blob[EDID_VERTICAL_HIGH_OFFSET]) >> 4) << 8))
data[EDID_WIDTH] = width
data[EDID_HEIGHT] = height
return data
def parse_edid_file(file_name):
with open(file_name, 'r') as edid_handle:
return parse_edid(edid_handle.read(EDID_MINIMAL_SIZE))
if __name__ == '__main__':
if len(sys.argv) < 2:
print parse_edid(sys.stdin.read())
else:
for edid_file in sys.argv[1:]:
print parse_edid_file(edid_file)