Kernel: Cleanup IHDA volume control and report the actual volume

This commit is contained in:
2026-08-19 21:32:36 +03:00
parent 36b34b0df0
commit 4aead25970
2 changed files with 35 additions and 33 deletions
@@ -67,6 +67,7 @@ namespace Kernel
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths; BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins; BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
size_t m_output_path_index { SIZE_MAX }; size_t m_output_path_index { SIZE_MAX };
size_t m_amplifier_idx { SIZE_MAX };
uint8_t m_stream_id { 0xFF }; uint8_t m_stream_id { 0xFF };
uint8_t m_stream_index { 0xFF }; uint8_t m_stream_index { 0xFF };
@@ -139,31 +139,27 @@ namespace Kernel
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB) BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
{ {
if (m_amplifier_idx == SIZE_MAX)
return BAN::Error::from_errno(ENOTSUP);
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB); mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
const auto& path = m_output_paths[m_output_path_index]; const auto* node = m_output_paths[m_output_path_index][m_amplifier_idx];
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const int32_t step_round = (mdB >= 0) const int32_t step_round = (mdB >= 0)
? +m_volume_info.step_mdB / 2 ? +m_volume_info.step_mdB / 2
: -m_volume_info.step_mdB / 2; : -m_volume_info.step_mdB / 2;
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset; const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + node->output_amplifier->offset;
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step; const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
TRY(m_controller->send_command({ TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF), .data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)), .command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id, .node_index = node->id,
.codec_address = m_cid, .codec_address = m_cid,
})); }));
break; m_volume_info.mdB = (mdB + step_round) / m_volume_info.step_mdB * m_volume_info.step_mdB;
}
m_volume_info.mdB = mdB;
return {}; return {};
} }
@@ -331,8 +327,8 @@ namespace Kernel
uint16_t HDAudioFunctionGroup::get_format_data() const uint16_t HDAudioFunctionGroup::get_format_data() const
{ {
// TODO: don't hardcode this // TODO: don't hardcode this
// format: PCM, 48 kHz, 16 bit, 2 channels // format: PCM, 48 kHz, 16 bit
return 0b0'0'000'000'0'001'0001; return 0b0'0'000'000'0'001'0000 | (get_channels() - 1);
} }
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index) BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
@@ -438,15 +434,25 @@ namespace Kernel
} }
} }
// update volume info to this path int32_t max_steps { 0 };
m_volume_info.min_mdB = 0; m_amplifier_idx = SIZE_MAX;
m_volume_info.max_mdB = 0;
m_volume_info.step_mdB = 0;
for (size_t i = 0; i < path.size(); i++) for (size_t i = 0; i < path.size(); i++)
{ {
if (!path[i]->output_amplifier.has_value()) if (!path[i]->output_amplifier.has_value())
continue; continue;
const auto& amp = path[i]->output_amplifier.value(); if (auto steps = path[i]->output_amplifier->num_steps; steps > max_steps)
{
max_steps = steps;
m_amplifier_idx = i;
}
}
if (m_amplifier_idx == SIZE_MAX)
m_volume_info = {};
else
{
const auto& amp = path[m_amplifier_idx]->output_amplifier.value();
const int32_t step_mdB = (amp.step_size + 1) * 250; const int32_t step_mdB = (amp.step_size + 1) * 250;
m_volume_info.step_mdB = step_mdB; m_volume_info.step_mdB = step_mdB;
@@ -463,16 +469,11 @@ namespace Kernel
TRY(m_controller->send_command({ TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF), .data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)), .command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id, .node_index = path[m_amplifier_idx]->id,
.codec_address = m_cid, .codec_address = m_cid,
})); }));
break;
} }
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
m_volume_info.mdB = 0;
return {}; return {};
} }