forked from Bananymous/banan-os
Kernel: Cleanup IHDA volume control and report the actual volume
This commit is contained in:
@@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user