blob: 22b8e6d5591502c01ec596e99afb62f598e49dc2 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "eld.h"
#include <src/lib/eld/eld.h>
namespace display {
void ComputeEld(const edid::Edid& edid, fbl::Array<uint8_t>& eld) {
// First we calculate the total length so we can allocate.
// The total ELD length of the ELD includes the ELD header, the ELD baseline (parts 1, 2 and 3)
// and the any vendor specific data (not suported).
// We need the baseline part 2 variable length from the monitor name.
// We populate up to kEldMonitorNameMaxLength bytes of monitor name.
constexpr size_t kMaxMonitorNameStringLength = 16;
size_t monitor_name_string_len = strlen(edid.monitor_name());
if (monitor_name_string_len > kMaxMonitorNameStringLength) {
monitor_name_string_len = kMaxMonitorNameStringLength;
}
const size_t eld_baseline_part2_length = monitor_name_string_len;
// We need the number of short audio descriptors to calculate the baseline part 3 length.
size_t number_of_short_audio_descriptors = 0;
for (auto it = edid::audio_data_block_iterator(&edid); it.is_valid(); ++it) {
if (it->format() != edid::ShortAudioDescriptor::kLPcm) {
// TODO(andresoportus): Add compressed formats.
continue;
}
number_of_short_audio_descriptors++;
}
const size_t eld_baseline_part3_length =
number_of_short_audio_descriptors * sizeof(edid::ShortAudioDescriptor);
// Now we can calculate the ELD length.
size_t eld_length = sizeof(hda::EldHeader) + sizeof(hda::EldBaselinePart1) +
eld_baseline_part2_length + eld_baseline_part3_length;
eld_length = (eld_length + 3) & ~3; // Make the ELD length multiple of 4.
// With the ELD length we can allocate and then fill in the data.
eld = fbl::Array<uint8_t>(new uint8_t[eld_length], eld_length);
memset(eld.get(), 0, eld_length); // Set reserved fields to 0.
// Fill the data, moving pointer p along the way.
uint8_t* p = eld.get();
// Populate the ELD header.
hda::EldHeader* header = reinterpret_cast<hda::EldHeader*>(p);
header->set_eld_ver(2);
header->set_baseline_eld_len(eld_length);
p += sizeof(hda::EldHeader);
// Populate the ELD baseline part 1.
hda::EldBaselinePart1* part1 = reinterpret_cast<hda::EldBaselinePart1*>(p);
// "with CEA-861-C and continuing through present, incrementing the version number is no longer
// required. The revision number shall be set to 0x03"
part1->set_cea_edid_ver(3);
part1->set_mnl(monitor_name_string_len);
part1->set_sad_count(number_of_short_audio_descriptors);
part1->set_conn_type(edid.is_hdmi() ? 0 : 1);
part1->set_s_ai(0); // Not supported: ACP, ISRC1, or ISRC2 packets.
part1->set_hdcp(0); // Not supported.
part1->aud_synch_delay = 0; // Not supported.
part1->byte4 = 0; // Not supported: FLR, LFE, FC, RLR, RC, FLRC, RLRC.
part1->port_id = 0; // Not supported.
part1->manufacturer_name = edid.manufacturer_name_code();
part1->product_code = edid.product_code();
p += sizeof(hda::EldBaselinePart1);
// Populate the ELD baseline part 2: monitor_name_string.
memcpy(p, edid.monitor_name(), monitor_name_string_len);
p += monitor_name_string_len;
// Populate the ELD baseline part 3: short audio descriptors.
for (auto it = edid::audio_data_block_iterator(&edid); it.is_valid(); ++it) {
if (it->format() != edid::ShortAudioDescriptor::kLPcm) {
// TODO(andresoportus): Add compressed formats.
continue;
}
edid::ShortAudioDescriptor* sad = reinterpret_cast<edid::ShortAudioDescriptor*>(p);
p += sizeof(edid::ShortAudioDescriptor);
*sad = *it;
}
// We don't populate the vendor specific block.
}
} // namespace display