1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file. 4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ui/display/util/edid_parser.h" 6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <algorithm> 8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/hash.h" 10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/string_util.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/sys_byteorder.h" 12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace ui { 14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace { 16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Returns 64-bit persistent ID for the specified manufacturer's ID and 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// product_code_hash, and the index of the output it is connected to. 19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// |output_index| is used to distinguish the displays of the same type. For 20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// example, swapping two identical display between two outputs will not be 21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// treated as swap. The 'serial number' field in EDID isn't used here because 22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// it is not guaranteed to have unique number and it may have the same fixed 23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// value (like 0). 24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochint64_t GetID(uint16_t manufacturer_id, 25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint32_t product_code_hash, 26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint8_t output_index) { 27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return ((static_cast<int64_t>(manufacturer_id) << 40) | 28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch (static_cast<int64_t>(product_code_hash) << 8) | output_index); 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} // namespace 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid, 34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint8_t output_index, 35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch int64_t* display_id_out) { 36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint16_t manufacturer_id = 0; 37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::string product_name; 38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // ParseOutputDeviceData fails if it doesn't have product_name. 40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ParseOutputDeviceData(edid, &manufacturer_id, &product_name); 41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Generates product specific value from product_name instead of product code. 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // See crbug.com/240341 44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint32_t product_code_hash = product_name.empty() ? 45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 0 : base::Hash(product_name); 46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (manufacturer_id != 0) { 47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // An ID based on display's index will be assigned later if this call 48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // fails. 49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *display_id_out = GetID( 50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch manufacturer_id, product_code_hash, output_index); 51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool ParseOutputDeviceData(const std::vector<uint8_t>& edid, 57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint16_t* manufacturer_id, 58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::string* human_readable_name) { 59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // See http://en.wikipedia.org/wiki/Extended_display_identification_data 60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // for the details of EDID data format. We use the following data: 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // bytes 8-9: manufacturer EISA ID, in big-endian 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // bytes 54-125: four descriptors (18-bytes each) which may contain 63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // the display name. 64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kManufacturerOffset = 8; 65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kManufacturerLength = 2; 66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kDescriptorOffset = 54; 67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kNumDescriptors = 4; 68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kDescriptorLength = 18; 69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // The specifier types. 70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned char kMonitorNameDescriptor = 0xfc; 71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (manufacturer_id) { 73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (edid.size() < kManufacturerOffset + kManufacturerLength) { 74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch LOG(ERROR) << "too short EDID data: manifacturer id"; 75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *manufacturer_id = 79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]); 80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if defined(ARCH_CPU_LITTLE_ENDIAN) 81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *manufacturer_id = base::ByteSwap(*manufacturer_id); 82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#endif 83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!human_readable_name) 86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch human_readable_name->clear(); 89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (unsigned int i = 0; i < kNumDescriptors; ++i) { 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength) 91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch size_t offset = kDescriptorOffset + i * kDescriptorLength; 94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If the descriptor contains the display name, it has the following 95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // structure: 96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // bytes 0-2, 4: \0 97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // byte 3: descriptor type, defined above. 98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // bytes 5-17: text data, ending with \r, padding with spaces 99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // we should check bytes 0-2 and 4, since it may have other values in 100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // case that the descriptor contains other type of data. 101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 && 102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) { 103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]), 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch kDescriptorLength - 5); 105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::TrimWhitespaceASCII( 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch found_name, base::TRIM_TRAILING, human_readable_name); 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Verify if the |human_readable_name| consists of printable characters only. 112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (size_t i = 0; i < human_readable_name->size(); ++i) { 113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch char c = (*human_readable_name)[i]; 114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!isascii(c) || !isprint(c)) { 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch human_readable_name->clear(); 116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch LOG(ERROR) << "invalid EDID: human unreadable char in name"; 117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, 125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bool* flag) { 126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // See http://en.wikipedia.org/wiki/Extended_display_identification_data 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // for the extension format of EDID. Also see EIA/CEA-861 spec for 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // the format of the extensions and how video capability is encoded. 129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 0: tag. should be 02h. 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 1: revision. only cares revision 3 (03h). 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 4-: data block. 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kExtensionBase = 128; 133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kExtensionSize = 128; 134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kNumExtensionsOffset = 126; 135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kDataBlockOffset = 4; 136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned char kCEAExtensionTag = '\x02'; 137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned char kExpectedExtensionRevision = '\x03'; 138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned char kExtendedTag = 7; 139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned char kExtendedVideoCapabilityTag = 0; 140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kPTOverscan = 4; 141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kITOverscan = 2; 142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const unsigned int kCEOverscan = 0; 143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (edid.size() <= kNumExtensionsOffset) 145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char num_extensions = edid[kNumExtensionsOffset]; 148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (size_t i = 0; i < num_extensions; ++i) { 150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Skip parsing the whole extension if size is not enough. 151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (edid.size() < kExtensionBase + (i + 1) * kExtensionSize) 152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch size_t extension_offset = kExtensionBase + i * kExtensionSize; 155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char tag = edid[extension_offset]; 156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char revision = edid[extension_offset + 1]; 157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision) 158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch continue; 159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char timing_descriptors_start = std::min( 161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch edid[extension_offset + 2], static_cast<unsigned char>(kExtensionSize)); 162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (size_t data_offset = extension_offset + kDataBlockOffset; 164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data_offset < extension_offset + timing_descriptors_start;) { 165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // A data block is encoded as: 166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 1 high 3 bits: tag. '07' for extended tags. 167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 1 remaining bits: the length of data block. 168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 2: the extended tag. '0' for video capability. 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // - byte 3: the capability. 170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char tag = edid[data_offset] >> 5; 171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch unsigned char payload_length = edid[data_offset] & 0x1f; 172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (data_offset + payload_length > edid.size()) 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (tag != kExtendedTag || payload_length < 2 || 176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch edid[data_offset + 1] != kExtendedVideoCapabilityTag) { 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data_offset += payload_length + 1; 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch continue; 179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // The difference between preferred, IT, and CE video formats 182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // doesn't matter. Sets |flag| to true if any of these flags are true. 183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if ((edid[data_offset + 2] & (1 << kPTOverscan)) || 184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch (edid[data_offset + 2] & (1 << kITOverscan)) || 185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch (edid[data_offset + 2] & (1 << kCEOverscan))) { 186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *flag = true; 187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else { 188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *flag = false; 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} // namespace ui 198