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<const HDAudio::AFGWidget*> m_output_pins;
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_index { 0xFF };
@@ -139,31 +139,27 @@ namespace Kernel
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);
const auto& path = m_output_paths[m_output_path_index];
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const auto* node = m_output_paths[m_output_path_index][m_amplifier_idx];
const int32_t step_round = (mdB >= 0)
? +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;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.node_index = node->id,
.codec_address = m_cid,
}));
break;
}
m_volume_info.mdB = mdB;
m_volume_info.mdB = (mdB + step_round) / m_volume_info.step_mdB * m_volume_info.step_mdB;
return {};
}
@@ -331,8 +327,8 @@ namespace Kernel
uint16_t HDAudioFunctionGroup::get_format_data() const
{
// TODO: don't hardcode this
// format: PCM, 48 kHz, 16 bit, 2 channels
return 0b0'0'000'000'0'001'0001;
// format: PCM, 48 kHz, 16 bit
return 0b0'0'000'000'0'001'0000 | (get_channels() - 1);
}
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
@@ -438,15 +434,25 @@ namespace Kernel
}
}
// update volume info to this path
m_volume_info.min_mdB = 0;
m_volume_info.max_mdB = 0;
m_volume_info.step_mdB = 0;
int32_t max_steps { 0 };
m_amplifier_idx = SIZE_MAX;
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
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;
m_volume_info.step_mdB = step_mdB;
@@ -463,16 +469,11 @@ namespace Kernel
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.node_index = path[m_amplifier_idx]->id,
.codec_address = m_cid,
}));
break;
}
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
m_volume_info.mdB = 0;
return {};
}