Kernel: Add mixer support to IHDA

This has not been tested as I don't have any hardware with mixers on
output paths :P
This commit is contained in:
2026-08-19 21:32:36 +03:00
parent 6cd3638a85
commit 1231b16cc3
3 changed files with 37 additions and 1 deletions
@@ -65,6 +65,7 @@ namespace Kernel::HDAudio
}; };
BAN::Optional<Amplifier> output_amplifier; BAN::Optional<Amplifier> output_amplifier;
BAN::Optional<Amplifier> input_amplifier;
BAN::Vector<uint16_t> connections; BAN::Vector<uint16_t> connections;
}; };
@@ -342,6 +342,7 @@ namespace Kernel
{ {
using HDAudio::AFGWidget; using HDAudio::AFGWidget;
case AFGWidget::Type::OutputConverter: case AFGWidget::Type::OutputConverter:
case AFGWidget::Type::Mixer:
case AFGWidget::Type::PinComplex: case AFGWidget::Type::PinComplex:
break; break;
default: default:
@@ -363,7 +364,7 @@ namespace Kernel
})); }));
// set connection index // set connection index
if (i + 1 < path.size() && path[i]->connections.size() > 1) if (i + 1 < path.size() && path[i]->connections.size() > 1 && path[i]->type != HDAudio::AFGWidget::Type::Mixer)
{ {
uint8_t index = 0; uint8_t index = 0;
for (; index < path[i]->connections.size(); index++) for (; index < path[i]->connections.size(); index++)
@@ -419,6 +420,25 @@ namespace Kernel
})); }));
break; break;
case AFGWidget::Type::Mixer:
if (path[i]->input_amplifier.has_value())
{
for (size_t idx = 0; idx < path[i]->connections.size(); idx++)
{
const uint8_t step = (path[i]->connections[idx] == path[i + 1]->id)
? path[i]->input_amplifier->offset
: 0b1'0000000;
const uint32_t volume = 0b0'1'1'1'0000'0'0000000 | (idx << 8) | 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,
.codec_address = m_cid,
}));
}
}
break;
case AFGWidget::Type::PinComplex: case AFGWidget::Type::PinComplex:
// enable output and H-Phn // enable output and H-Phn
TRY(m_controller->send_command({ TRY(m_controller->send_command({
@@ -504,6 +524,7 @@ namespace Kernel
using HDAudio::AFGWidget; using HDAudio::AFGWidget;
case AFGWidget::Type::OutputConverter: case AFGWidget::Type::OutputConverter:
case AFGWidget::Type::Mixer:
break; break;
case AFGWidget::Type::PinComplex: case AFGWidget::Type::PinComplex:
@@ -333,6 +333,20 @@ namespace Kernel
}; };
} }
if (const uint32_t in_amp_cap = send_command_or_zero(0xF00, 0x0D))
{
const uint8_t offset = (in_amp_cap >> 0) & 0x7F;
const uint8_t num_steps = (in_amp_cap >> 8) & 0x7F;
const uint8_t step_size = (in_amp_cap >> 16) & 0x7F;
const bool mute = (in_amp_cap >> 31);
result.input_amplifier = HDAudio::AFGWidget::Amplifier {
.offset = offset,
.num_steps = num_steps,
.step_size = step_size,
.mute = mute,
};
}
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E); const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1; const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
const uint8_t conn_count = connection_info & 0x3F; const uint8_t conn_count = connection_info & 0x3F;