summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Devices/Audio/AC97.cpp46
-rw-r--r--Kernel/Devices/Audio/AC97.h11
-rw-r--r--Kernel/Devices/Audio/SB16.cpp7
-rw-r--r--Userland/Services/AudioServer/AudioServer.ipc4
-rw-r--r--Userland/Services/AudioServer/ClientConnection.cpp2
-rw-r--r--Userland/Services/AudioServer/ClientConnection.h2
-rw-r--r--Userland/Services/AudioServer/Mixer.cpp6
-rw-r--r--Userland/Services/AudioServer/Mixer.h4
-rw-r--r--Userland/Utilities/asctl.cpp2
9 files changed, 56 insertions, 28 deletions
diff --git a/Kernel/Devices/Audio/AC97.cpp b/Kernel/Devices/Audio/AC97.cpp
index f2e0302cf9..c8161ddff0 100644
--- a/Kernel/Devices/Audio/AC97.cpp
+++ b/Kernel/Devices/Audio/AC97.cpp
@@ -13,6 +13,10 @@ namespace Kernel {
static constexpr int buffer_descriptor_list_max_entries = 32;
+// 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_maximum = 48000;
+
static ErrorOr<OwnPtr<Memory::Region>> allocate_physical_buffer(size_t size, StringView name)
{
auto vmobject = TRY(Memory::AnonymousVMObject::try_create_physically_contiguous_with_size(Memory::page_round_up(size)));
@@ -92,22 +96,31 @@ UNMAP_AFTER_INIT void AC97::initialize()
auto control = m_io_bus_base.offset(NativeAudioBusRegister::GlobalControl).in<u32>();
control |= GlobalControlFlag::GPIInterruptEnable;
control |= GlobalControlFlag::AC97ColdReset;
- m_io_bus_base.offset(NativeAudioBusRegister::GlobalControl).out<u32>(control);
+ m_io_bus_base.offset(NativeAudioBusRegister::GlobalControl).out(control);
// Reset mixer
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>();
- VERIFY((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) == 1);
+ VERIFY((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) > 0);
VERIFY((extended_audio_id & ExtendedAudioMask::Revision) >> 10 == AC97Revision::Revision23);
+ // Enable 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 = extended_audio_status_control_register.in<u16>();
+ extended_audio_status |= ExtendedAudioStatusControlFlag::DoubleRateAudio;
+ extended_audio_status_control_register.out(extended_audio_status);
+ m_double_rate_pcm_enabled = true;
+ }
+
+ MUST(set_pcm_output_sample_rate(m_sample_rate));
+
// Left and right volume of 0 means attenuation of 0 dB
set_master_output_volume(0, 0, Muted::No);
set_pcm_output_volume(0, 0, Muted::No);
- set_pcm_output_sample_rate(m_sample_rate);
-
reset_pcm_out();
enable_irq();
}
@@ -116,15 +129,14 @@ ErrorOr<void> AC97::ioctl(OpenFileDescription&, unsigned request, Userspace<void
{
switch (request) {
case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: {
- auto output = static_ptr_cast<u16*>(arg);
+ auto output = static_ptr_cast<u32*>(arg);
return copy_to_user(output, &m_sample_rate);
}
case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
- auto sample_rate_value = static_cast<u16>(arg.ptr());
- if (sample_rate_value == 0)
- return EINVAL;
- if (m_sample_rate != sample_rate_value)
- set_pcm_output_sample_rate(sample_rate_value);
+ auto sample_rate = static_cast<u32>(arg.ptr());
+ if (sample_rate == m_sample_rate)
+ return {};
+ TRY(set_pcm_output_sample_rate(sample_rate));
return {};
}
default:
@@ -151,12 +163,20 @@ void AC97::set_master_output_volume(u8 left_channel, u8 right_channel, Muted mut
m_io_mixer_base.offset(NativeAudioMixerRegister::SetMasterOutputVolume).out(volume_value);
}
-void AC97::set_pcm_output_sample_rate(u16 sample_rate)
+ErrorOr<void> AC97::set_pcm_output_sample_rate(u32 sample_rate)
{
+ auto const double_rate_shift = m_double_rate_pcm_enabled ? 1 : 0;
+ auto shifted_sample_rate = sample_rate >> double_rate_shift;
+ if (shifted_sample_rate < pcm_sample_rate_minimum || shifted_sample_rate > pcm_sample_rate_maximum)
+ return ENOTSUP;
+
auto pcm_front_dac_rate_register = m_io_mixer_base.offset(NativeAudioMixerRegister::PCMFrontDACRate);
- pcm_front_dac_rate_register.out(sample_rate);
- m_sample_rate = pcm_front_dac_rate_register.in<u16>();
+ pcm_front_dac_rate_register.out<u16>(shifted_sample_rate);
+ m_sample_rate = static_cast<u32>(pcm_front_dac_rate_register.in<u16>()) << double_rate_shift;
+
dbgln("AC97 @ {}: PCM front DAC rate set to {} Hz", pci_address(), m_sample_rate);
+
+ return {};
}
void AC97::set_pcm_output_volume(u8 left_channel, u8 right_channel, Muted mute)
diff --git a/Kernel/Devices/Audio/AC97.h b/Kernel/Devices/Audio/AC97.h
index db85ad5452..0fa5a51d41 100644
--- a/Kernel/Devices/Audio/AC97.h
+++ b/Kernel/Devices/Audio/AC97.h
@@ -43,14 +43,20 @@ private:
SetMasterOutputVolume = 0x02,
SetPCMOutputVolume = 0x18,
ExtendedAudioID = 0x28,
+ ExtendedAudioStatusControl = 0x2a,
PCMFrontDACRate = 0x2c,
};
enum ExtendedAudioMask : u16 {
VariableRatePCMAudio = 1 << 0,
+ DoubleRatePCMAudio = 1 << 1,
Revision = 3 << 10,
};
+ enum ExtendedAudioStatusControlFlag : u16 {
+ DoubleRateAudio = 1 << 1,
+ };
+
enum AC97Revision : u8 {
Revision21OrEarlier = 0b00,
Revision22 = 0b01,
@@ -150,12 +156,13 @@ private:
void initialize();
void reset_pcm_out();
void set_master_output_volume(u8, u8, Muted);
- void set_pcm_output_sample_rate(u16);
+ ErrorOr<void> set_pcm_output_sample_rate(u32);
void set_pcm_output_volume(u8, u8, Muted);
ErrorOr<void> write_single_buffer(UserOrKernelBuffer const&, size_t, size_t);
OwnPtr<Memory::Region> m_buffer_descriptor_list;
u8 m_buffer_descriptor_list_index = 0;
+ bool m_double_rate_pcm_enabled = false;
IOAddress m_io_mixer_base;
IOAddress m_io_bus_base;
WaitQueue m_irq_queue;
@@ -163,7 +170,7 @@ private:
u8 m_output_buffer_page_count = 4;
u8 m_output_buffer_page_index = 0;
AC97Channel m_pcm_out_channel;
- u16 m_sample_rate = 44100;
+ u32 m_sample_rate = 44100;
};
}
diff --git a/Kernel/Devices/Audio/SB16.cpp b/Kernel/Devices/Audio/SB16.cpp
index e5bfef119d..ce2cdc8d63 100644
--- a/Kernel/Devices/Audio/SB16.cpp
+++ b/Kernel/Devices/Audio/SB16.cpp
@@ -123,9 +123,10 @@ ErrorOr<void> SB16::ioctl(OpenFileDescription&, unsigned request, Userspace<void
return copy_to_user(output, &m_sample_rate);
}
case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
- auto sample_rate_value = static_cast<u16>(arg.ptr());
- if (sample_rate_value == 0)
- return EINVAL;
+ auto sample_rate_input = static_cast<u32>(arg.ptr());
+ if (sample_rate_input == 0 || sample_rate_input > 44100)
+ return ENOTSUP;
+ auto sample_rate_value = static_cast<u16>(sample_rate_input);
if (m_sample_rate != sample_rate_value)
set_sample_rate(sample_rate_value);
return {};
diff --git a/Userland/Services/AudioServer/AudioServer.ipc b/Userland/Services/AudioServer/AudioServer.ipc
index f34a84532b..d0396bad7e 100644
--- a/Userland/Services/AudioServer/AudioServer.ipc
+++ b/Userland/Services/AudioServer/AudioServer.ipc
@@ -11,8 +11,8 @@ endpoint AudioServer
set_self_volume(double volume) => ()
// Audio device
- set_sample_rate(u16 sample_rate) => ()
- get_sample_rate() => (u16 sample_rate)
+ set_sample_rate(u32 sample_rate) => ()
+ get_sample_rate() => (u32 sample_rate)
// Buffer playback
enqueue_buffer(Core::AnonymousBuffer buffer, i32 buffer_id, int sample_count) => (bool success)
diff --git a/Userland/Services/AudioServer/ClientConnection.cpp b/Userland/Services/AudioServer/ClientConnection.cpp
index be04b960b5..ee84a59536 100644
--- a/Userland/Services/AudioServer/ClientConnection.cpp
+++ b/Userland/Services/AudioServer/ClientConnection.cpp
@@ -73,7 +73,7 @@ Messages::AudioServer::GetSampleRateResponse ClientConnection::get_sample_rate()
return { m_mixer.audiodevice_get_sample_rate() };
}
-void ClientConnection::set_sample_rate(u16 sample_rate)
+void ClientConnection::set_sample_rate(u32 sample_rate)
{
m_mixer.audiodevice_set_sample_rate(sample_rate);
}
diff --git a/Userland/Services/AudioServer/ClientConnection.h b/Userland/Services/AudioServer/ClientConnection.h
index a4d2d6a177..be5458d4e1 100644
--- a/Userland/Services/AudioServer/ClientConnection.h
+++ b/Userland/Services/AudioServer/ClientConnection.h
@@ -49,7 +49,7 @@ private:
virtual Messages::AudioServer::GetPlayingBufferResponse get_playing_buffer() override;
virtual Messages::AudioServer::GetMutedResponse get_muted() override;
virtual void set_muted(bool) override;
- virtual void set_sample_rate(u16 sample_rate) override;
+ virtual void set_sample_rate(u32 sample_rate) override;
virtual Messages::AudioServer::GetSampleRateResponse get_sample_rate() override;
Mixer& m_mixer;
diff --git a/Userland/Services/AudioServer/Mixer.cpp b/Userland/Services/AudioServer/Mixer.cpp
index 04b95c138e..27b6daf1bf 100644
--- a/Userland/Services/AudioServer/Mixer.cpp
+++ b/Userland/Services/AudioServer/Mixer.cpp
@@ -165,7 +165,7 @@ void Mixer::set_muted(bool muted)
});
}
-int Mixer::audiodevice_set_sample_rate(u16 sample_rate)
+int Mixer::audiodevice_set_sample_rate(u32 sample_rate)
{
int code = ioctl(m_device->fd(), SOUNDCARD_IOCTL_SET_SAMPLE_RATE, sample_rate);
if (code != 0)
@@ -173,9 +173,9 @@ int Mixer::audiodevice_set_sample_rate(u16 sample_rate)
return code;
}
-u16 Mixer::audiodevice_get_sample_rate() const
+u32 Mixer::audiodevice_get_sample_rate() const
{
- u16 sample_rate = 0;
+ u32 sample_rate = 0;
int code = ioctl(m_device->fd(), SOUNDCARD_IOCTL_GET_SAMPLE_RATE, &sample_rate);
if (code != 0)
dbgln("Error while getting sample rate: ioctl error: {}", strerror(errno));
diff --git a/Userland/Services/AudioServer/Mixer.h b/Userland/Services/AudioServer/Mixer.h
index 0cd48c8500..9c64ab0eec 100644
--- a/Userland/Services/AudioServer/Mixer.h
+++ b/Userland/Services/AudioServer/Mixer.h
@@ -119,8 +119,8 @@ public:
bool is_muted() const { return m_muted; }
void set_muted(bool);
- int audiodevice_set_sample_rate(u16 sample_rate);
- u16 audiodevice_get_sample_rate() const;
+ int audiodevice_set_sample_rate(u32 sample_rate);
+ u32 audiodevice_get_sample_rate() const;
private:
Mixer(NonnullRefPtr<Core::ConfigFile> config);
diff --git a/Userland/Utilities/asctl.cpp b/Userland/Utilities/asctl.cpp
index c2ffe42db8..8d064880d7 100644
--- a/Userland/Utilities/asctl.cpp
+++ b/Userland/Utilities/asctl.cpp
@@ -81,7 +81,7 @@ int main(int argc, char** argv)
break;
}
case AudioVariable::SampleRate: {
- u16 sample_rate = audio_client->get_sample_rate();
+ u32 sample_rate = audio_client->get_sample_rate();
if (human_mode)
outln("Sample rate: {:5d} Hz", sample_rate);
else