mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:47:35 +00:00
Kernel: Implement variable rate audio support for AC97 devices
Previously we `VERIFY()`ed that the device supports variable-rate audio (VRA). Now, we query the VRA bit and if VRA is not supported, we do not enable double-rate audio and disallow setting any sample rate except the fixed 48kHz rate as defined by the AC'97 specification. This should allow the driver to function on a wider array of hardware. Note that in the AC'97 specification, DRA without VRA is allowed when supported: this effectively doubles the sample rate to 96kHZ. For now, we ignore that possibility and let it default to 48kHZ.
This commit is contained in:
parent
377a984905
commit
58bcb93777
2 changed files with 23 additions and 11 deletions
|
@ -13,6 +13,9 @@ namespace Kernel {
|
||||||
|
|
||||||
static constexpr int buffer_descriptor_list_max_entries = 32;
|
static constexpr int buffer_descriptor_list_max_entries = 32;
|
||||||
|
|
||||||
|
static constexpr u16 pcm_default_sample_rate = 44100;
|
||||||
|
static constexpr u16 pcm_fixed_sample_rate = 48000;
|
||||||
|
|
||||||
// Valid output range - with double-rate enabled, sample rate can go up to 96kHZ
|
// Valid output range - with double-rate enabled, sample rate can go up to 96kHZ
|
||||||
static constexpr u16 pcm_sample_rate_minimum = 8000;
|
static constexpr u16 pcm_sample_rate_minimum = 8000;
|
||||||
static constexpr u16 pcm_sample_rate_maximum = 48000;
|
static constexpr u16 pcm_sample_rate_maximum = 48000;
|
||||||
|
@ -101,21 +104,25 @@ UNMAP_AFTER_INIT void AC97::initialize()
|
||||||
// Reset mixer
|
// Reset mixer
|
||||||
m_io_mixer_base.offset(NativeAudioMixerRegister::Reset).out<u16>(1);
|
m_io_mixer_base.offset(NativeAudioMixerRegister::Reset).out<u16>(1);
|
||||||
|
|
||||||
// Verify extended capabilities
|
|
||||||
auto extended_audio_id = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioID).in<u16>();
|
auto extended_audio_id = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioID).in<u16>();
|
||||||
VERIFY((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) > 0);
|
|
||||||
VERIFY((extended_audio_id & ExtendedAudioMask::Revision) >> 10 == AC97Revision::Revision23);
|
VERIFY((extended_audio_id & ExtendedAudioMask::Revision) >> 10 == AC97Revision::Revision23);
|
||||||
|
|
||||||
// Enable double rate PCM audio if supported
|
// Enable variable and double rate PCM audio if supported
|
||||||
if ((extended_audio_id & ExtendedAudioMask::DoubleRatePCMAudio) > 0) {
|
auto extended_audio_status_control_register = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioStatusControl);
|
||||||
auto extended_audio_status_control_register = m_io_mixer_base.offset(NativeAudioMixerRegister::ExtendedAudioStatusControl);
|
auto extended_audio_status = extended_audio_status_control_register.in<u16>();
|
||||||
auto extended_audio_status = extended_audio_status_control_register.in<u16>();
|
if ((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) > 0) {
|
||||||
|
extended_audio_status |= ExtendedAudioStatusControlFlag::VariableRateAudio;
|
||||||
|
m_variable_rate_pcm_supported = true;
|
||||||
|
}
|
||||||
|
if (!m_variable_rate_pcm_supported) {
|
||||||
|
extended_audio_status &= ~ExtendedAudioStatusControlFlag::DoubleRateAudio;
|
||||||
|
} else if ((extended_audio_id & ExtendedAudioMask::DoubleRatePCMAudio) > 0) {
|
||||||
extended_audio_status |= ExtendedAudioStatusControlFlag::DoubleRateAudio;
|
extended_audio_status |= ExtendedAudioStatusControlFlag::DoubleRateAudio;
|
||||||
extended_audio_status_control_register.out(extended_audio_status);
|
|
||||||
m_double_rate_pcm_enabled = true;
|
m_double_rate_pcm_enabled = true;
|
||||||
}
|
}
|
||||||
|
extended_audio_status_control_register.out(extended_audio_status);
|
||||||
|
|
||||||
MUST(set_pcm_output_sample_rate(m_sample_rate));
|
MUST(set_pcm_output_sample_rate(m_variable_rate_pcm_supported ? pcm_default_sample_rate : pcm_fixed_sample_rate));
|
||||||
|
|
||||||
// Left and right volume of 0 means attenuation of 0 dB
|
// Left and right volume of 0 means attenuation of 0 dB
|
||||||
set_master_output_volume(0, 0, Muted::No);
|
set_master_output_volume(0, 0, Muted::No);
|
||||||
|
@ -134,8 +141,6 @@ ErrorOr<void> AC97::ioctl(OpenFileDescription&, unsigned request, Userspace<void
|
||||||
}
|
}
|
||||||
case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
|
case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
|
||||||
auto sample_rate = static_cast<u32>(arg.ptr());
|
auto sample_rate = static_cast<u32>(arg.ptr());
|
||||||
if (sample_rate == m_sample_rate)
|
|
||||||
return {};
|
|
||||||
TRY(set_pcm_output_sample_rate(sample_rate));
|
TRY(set_pcm_output_sample_rate(sample_rate));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -165,8 +170,13 @@ void AC97::set_master_output_volume(u8 left_channel, u8 right_channel, Muted mut
|
||||||
|
|
||||||
ErrorOr<void> AC97::set_pcm_output_sample_rate(u32 sample_rate)
|
ErrorOr<void> AC97::set_pcm_output_sample_rate(u32 sample_rate)
|
||||||
{
|
{
|
||||||
|
if (m_sample_rate == sample_rate)
|
||||||
|
return {};
|
||||||
|
|
||||||
auto const double_rate_shift = m_double_rate_pcm_enabled ? 1 : 0;
|
auto const double_rate_shift = m_double_rate_pcm_enabled ? 1 : 0;
|
||||||
auto shifted_sample_rate = sample_rate >> double_rate_shift;
|
auto shifted_sample_rate = sample_rate >> double_rate_shift;
|
||||||
|
if (!m_variable_rate_pcm_supported && shifted_sample_rate != pcm_fixed_sample_rate)
|
||||||
|
return ENOTSUP;
|
||||||
if (shifted_sample_rate < pcm_sample_rate_minimum || shifted_sample_rate > pcm_sample_rate_maximum)
|
if (shifted_sample_rate < pcm_sample_rate_minimum || shifted_sample_rate > pcm_sample_rate_maximum)
|
||||||
return ENOTSUP;
|
return ENOTSUP;
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExtendedAudioStatusControlFlag : u16 {
|
enum ExtendedAudioStatusControlFlag : u16 {
|
||||||
|
VariableRateAudio = 1 << 0,
|
||||||
DoubleRateAudio = 1 << 1,
|
DoubleRateAudio = 1 << 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -170,7 +171,8 @@ private:
|
||||||
u8 m_output_buffer_page_count = 4;
|
u8 m_output_buffer_page_count = 4;
|
||||||
u8 m_output_buffer_page_index = 0;
|
u8 m_output_buffer_page_index = 0;
|
||||||
AC97Channel m_pcm_out_channel;
|
AC97Channel m_pcm_out_channel;
|
||||||
u32 m_sample_rate = 44100;
|
u32 m_sample_rate = 0;
|
||||||
|
bool m_variable_rate_pcm_supported = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue