Serenity Operating System
at master 333 lines 14 kB view raw
1/* 2 * Copyright (c) 2021-2022, Jelle Raaijmakers <jelle@gmta.nl> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Format.h> 8#include <Kernel/Arch/Delay.h> 9#include <Kernel/Devices/Audio/AC97.h> 10#include <Kernel/Devices/DeviceManagement.h> 11#include <Kernel/InterruptDisabler.h> 12#include <Kernel/Memory/AnonymousVMObject.h> 13 14namespace Kernel { 15 16static constexpr int buffer_descriptor_list_max_entries = 32; 17 18static constexpr u16 pcm_default_sample_rate = 44100; 19static constexpr u16 pcm_fixed_sample_rate = 48000; 20 21// Valid output range - with double-rate enabled, sample rate can go up to 96kHZ 22static constexpr u16 pcm_sample_rate_minimum = 8000; 23static constexpr u16 pcm_sample_rate_maximum = 48000; 24 25UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<AC97>> AC97::try_create(PCI::DeviceIdentifier const& pci_device_identifier) 26{ 27 auto mixer_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); 28 auto bus_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR1)); 29 30 auto pcm_out_channel_io_window = TRY(bus_io_window->create_from_io_window_with_offset(NativeAudioBusChannel::PCMOutChannel)); 31 auto pcm_out_channel = TRY(AC97Channel::create_with_parent_pci_device(pci_device_identifier.address(), "PCMOut"sv, move(pcm_out_channel_io_window))); 32 33 auto ac97 = adopt_nonnull_lock_ref_or_enomem(new (nothrow) AC97(pci_device_identifier, move(pcm_out_channel), move(mixer_io_window), move(bus_io_window))); 34 if (!ac97.is_error()) 35 TRY(ac97.value()->initialize()); 36 return ac97; 37} 38 39UNMAP_AFTER_INIT AC97::AC97(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr<AC97Channel> pcm_out_channel, NonnullOwnPtr<IOWindow> mixer_io_window, NonnullOwnPtr<IOWindow> bus_io_window) 40 : PCI::Device(const_cast<PCI::DeviceIdentifier&>(pci_device_identifier)) 41 , IRQHandler(pci_device_identifier.interrupt_line().value()) 42 , m_mixer_io_window(move(mixer_io_window)) 43 , m_bus_io_window(move(bus_io_window)) 44 , m_pcm_out_channel(move(pcm_out_channel)) 45{ 46} 47 48UNMAP_AFTER_INIT AC97::~AC97() = default; 49 50bool AC97::handle_irq(RegisterState const&) 51{ 52 auto pcm_out_status = m_pcm_out_channel->io_window().read16(AC97Channel::Register::Status); 53 dbgln_if(AC97_DEBUG, "AC97 @ {}: interrupt received - status: {:#05b}", device_identifier().address(), pcm_out_status); 54 55 bool is_dma_halted = (pcm_out_status & AudioStatusRegisterFlag::DMAControllerHalted) > 0; 56 bool current_equals_last_valid = (pcm_out_status & AudioStatusRegisterFlag::CurrentEqualsLastValid) > 0; 57 bool is_completion_interrupt = (pcm_out_status & AudioStatusRegisterFlag::BufferCompletionInterruptStatus) > 0; 58 bool is_fifo_error = (pcm_out_status & AudioStatusRegisterFlag::FIFOError) > 0; 59 VERIFY(!is_fifo_error); 60 61 // If there is no buffer completion, we're not going to do anything 62 if (!is_completion_interrupt) 63 return false; 64 65 // On interrupt, we need to reset PCM interrupt flags by setting their bits 66 pcm_out_status = AudioStatusRegisterFlag::LastValidBufferCompletionInterrupt 67 | AudioStatusRegisterFlag::BufferCompletionInterruptStatus 68 | AudioStatusRegisterFlag::FIFOError; 69 m_pcm_out_channel->io_window().write16(AC97Channel::Register::Status, pcm_out_status); 70 71 if (is_dma_halted) { 72 VERIFY(current_equals_last_valid); 73 m_pcm_out_channel->handle_dma_stopped(); 74 } 75 76 if (!m_irq_queue.is_empty()) 77 m_irq_queue.wake_all(); 78 79 return true; 80} 81 82UNMAP_AFTER_INIT ErrorOr<void> AC97::initialize() 83{ 84 dbgln_if(AC97_DEBUG, "AC97 @ {}: mixer base: {:#04x}", device_identifier().address(), m_mixer_io_window); 85 dbgln_if(AC97_DEBUG, "AC97 @ {}: bus base: {:#04x}", device_identifier().address(), m_bus_io_window); 86 87 // Read out AC'97 codec revision and vendor 88 auto extended_audio_id = m_mixer_io_window->read16(NativeAudioMixerRegister::ExtendedAudioID); 89 m_codec_revision = static_cast<AC97Revision>(((extended_audio_id & ExtendedAudioMask::Revision) >> 10) & 0b11); 90 dbgln_if(AC97_DEBUG, "AC97 @ {}: codec revision {:#02b}", device_identifier().address(), to_underlying(m_codec_revision)); 91 if (m_codec_revision == AC97Revision::Reserved) 92 return ENOTSUP; 93 94 // Report vendor / device ID 95 u32 vendor_id = m_mixer_io_window->read16(NativeAudioMixerRegister::VendorID1) << 16 | m_mixer_io_window->read16(NativeAudioMixerRegister::VendorID2); 96 dmesgln_pci(*this, "Vendor ID: {:#8x}", vendor_id); 97 98 // Bus cold reset, enable interrupts 99 enable_pin_based_interrupts(); 100 PCI::enable_bus_mastering(device_identifier()); 101 auto control = m_bus_io_window->read32(NativeAudioBusRegister::GlobalControl); 102 control |= GlobalControlFlag::GPIInterruptEnable; 103 control |= GlobalControlFlag::AC97ColdReset; 104 m_bus_io_window->write32(NativeAudioBusRegister::GlobalControl, control); 105 106 // Reset mixer 107 m_mixer_io_window->write16(NativeAudioMixerRegister::Reset, 1); 108 109 // Enable variable and double rate PCM audio if supported 110 auto extended_audio_status = m_mixer_io_window->read16(NativeAudioMixerRegister::ExtendedAudioStatusControl); 111 if ((extended_audio_id & ExtendedAudioMask::VariableRatePCMAudio) > 0) { 112 extended_audio_status |= ExtendedAudioStatusControlFlag::VariableRateAudio; 113 m_variable_rate_pcm_supported = true; 114 } 115 if (!m_variable_rate_pcm_supported) { 116 extended_audio_status &= ~ExtendedAudioStatusControlFlag::DoubleRateAudio; 117 } else if ((extended_audio_id & ExtendedAudioMask::DoubleRatePCMAudio) > 0) { 118 extended_audio_status |= ExtendedAudioStatusControlFlag::DoubleRateAudio; 119 m_double_rate_pcm_enabled = true; 120 } 121 m_mixer_io_window->write16(NativeAudioMixerRegister::ExtendedAudioStatusControl, extended_audio_status); 122 123 TRY(set_pcm_output_sample_rate(m_variable_rate_pcm_supported ? pcm_default_sample_rate : pcm_fixed_sample_rate)); 124 125 // Left and right volume of 0 means attenuation of 0 dB 126 set_master_output_volume(0, 0, Muted::No); 127 set_pcm_output_volume(0, 0, Muted::No); 128 129 m_pcm_out_channel->reset(); 130 enable_irq(); 131 return {}; 132} 133 134void AC97::set_master_output_volume(u8 left_channel, u8 right_channel, Muted mute) 135{ 136 u16 volume_value = ((right_channel & 63) << 0) 137 | ((left_channel & 63) << 8) 138 | ((mute == Muted::Yes ? 1 : 0) << 15); 139 m_mixer_io_window->write16(NativeAudioMixerRegister::SetMasterOutputVolume, volume_value); 140} 141 142ErrorOr<void> AC97::set_pcm_output_sample_rate(u32 sample_rate) 143{ 144 if (m_sample_rate == sample_rate) 145 return {}; 146 147 auto const double_rate_shift = m_double_rate_pcm_enabled ? 1 : 0; 148 auto shifted_sample_rate = sample_rate >> double_rate_shift; 149 if (!m_variable_rate_pcm_supported && shifted_sample_rate != pcm_fixed_sample_rate) 150 return ENOTSUP; 151 if (shifted_sample_rate < pcm_sample_rate_minimum || shifted_sample_rate > pcm_sample_rate_maximum) 152 return ENOTSUP; 153 154 m_mixer_io_window->write16(NativeAudioMixerRegister::PCMFrontDACRate, shifted_sample_rate); 155 m_sample_rate = static_cast<u32>(m_mixer_io_window->read16(NativeAudioMixerRegister::PCMFrontDACRate)) << double_rate_shift; 156 157 dmesgln_pci(*this, "PCM front DAC rate set to {} Hz", m_sample_rate); 158 159 // Setting the sample rate stops a running DMA engine, so restart it 160 if (m_pcm_out_channel->dma_running()) 161 m_pcm_out_channel->start_dma(); 162 163 return {}; 164} 165 166void AC97::set_pcm_output_volume(u8 left_channel, u8 right_channel, Muted mute) 167{ 168 u16 volume_value = ((right_channel & 31) << 0) 169 | ((left_channel & 31) << 8) 170 | ((mute == Muted::Yes ? 1 : 0) << 15); 171 m_mixer_io_window->write16(NativeAudioMixerRegister::SetPCMOutputVolume, volume_value); 172} 173 174LockRefPtr<AudioChannel> AC97::audio_channel(u32 index) const 175{ 176 if (index == 0) 177 return m_audio_channel; 178 return {}; 179} 180 181void AC97::detect_hardware_audio_channels(Badge<AudioManagement>) 182{ 183 m_audio_channel = AudioChannel::must_create(*this, 0); 184} 185 186ErrorOr<void> AC97::set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) 187{ 188 if (channel_index != 0) 189 return ENODEV; 190 TRY(set_pcm_output_sample_rate(samples_per_second_rate)); 191 return {}; 192} 193 194ErrorOr<u32> AC97::get_pcm_output_sample_rate(size_t channel_index) 195{ 196 if (channel_index != 0) 197 return Error::from_errno(ENODEV); 198 return m_sample_rate; 199} 200 201ErrorOr<size_t> AC97::write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) 202{ 203 if (channel_index != 0) 204 return Error::from_errno(ENODEV); 205 206 if (!m_output_buffer) 207 m_output_buffer = TRY(MM.allocate_dma_buffer_pages(m_output_buffer_page_count * PAGE_SIZE, "AC97 Output buffer"sv, Memory::Region::Access::Write)); 208 209 if (!m_buffer_descriptor_list) { 210 size_t buffer_descriptor_list_size = buffer_descriptor_list_max_entries * sizeof(BufferDescriptorListEntry); 211 buffer_descriptor_list_size = TRY(Memory::page_round_up(buffer_descriptor_list_size)); 212 m_buffer_descriptor_list = TRY(MM.allocate_dma_buffer_pages(buffer_descriptor_list_size, "AC97 Buffer Descriptor List"sv, Memory::Region::Access::Write)); 213 } 214 215 Checked<size_t> remaining = length; 216 size_t offset = 0; 217 while (remaining > static_cast<size_t>(0)) { 218 TRY(write_single_buffer(data, offset, min(remaining.value(), PAGE_SIZE))); 219 offset += PAGE_SIZE; 220 remaining.saturating_sub(PAGE_SIZE); 221 } 222 223 return length; 224} 225 226ErrorOr<void> AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t offset, size_t length) 227{ 228 VERIFY(length <= PAGE_SIZE); 229 230 { 231 // Block until we can write into an unused buffer 232 InterruptDisabler disabler; 233 do { 234 auto pcm_out_status = m_pcm_out_channel->io_window().read16(AC97Channel::Register::Status); 235 auto current_index = m_pcm_out_channel->io_window().read8(AC97Channel::Register::CurrentIndexValue); 236 int last_valid_index = m_pcm_out_channel->io_window().read8(AC97Channel::Register::LastValidIndex); 237 238 auto head_distance = last_valid_index - current_index; 239 if (head_distance < 0) 240 head_distance += buffer_descriptor_list_max_entries; 241 if (m_pcm_out_channel->dma_running()) 242 ++head_distance; 243 244 // Current index has _passed_ last valid index - move our list index up 245 if (head_distance > m_output_buffer_page_count) { 246 m_buffer_descriptor_list_index = current_index + 1; 247 break; 248 } 249 250 // There is room for our data 251 if (head_distance < m_output_buffer_page_count) 252 break; 253 254 dbgln_if(AC97_DEBUG, "AC97 @ {}: waiting on interrupt - status: {:#05b} CI: {} LVI: {}", device_identifier().address(), pcm_out_status, current_index, last_valid_index); 255 m_irq_queue.wait_forever("AC97"sv); 256 } while (m_pcm_out_channel->dma_running()); 257 } 258 // Copy data from userspace into one of our buffers 259 TRY(data.read(m_output_buffer->vaddr_from_page_index(m_output_buffer_page_index).as_ptr(), offset, length)); 260 261 // Write the next entry to the buffer descriptor list 262 u16 number_of_samples = length / sizeof(u16); 263 auto list_entries = reinterpret_cast<BufferDescriptorListEntry*>(m_buffer_descriptor_list->vaddr().get()); 264 auto list_entry = &list_entries[m_buffer_descriptor_list_index]; 265 list_entry->buffer_pointer = static_cast<u32>(m_output_buffer->physical_page(m_output_buffer_page_index)->paddr().get()); 266 list_entry->control_and_length = number_of_samples | BufferDescriptorListEntryFlags::InterruptOnCompletion; 267 268 auto buffer_address = static_cast<u32>(m_buffer_descriptor_list->physical_page(0)->paddr().get()); 269 m_pcm_out_channel->set_last_valid_index(buffer_address, m_buffer_descriptor_list_index); 270 271 if (!m_pcm_out_channel->dma_running()) 272 m_pcm_out_channel->start_dma(); 273 274 m_output_buffer_page_index = (m_output_buffer_page_index + 1) % m_output_buffer_page_count; 275 m_buffer_descriptor_list_index = (m_buffer_descriptor_list_index + 1) % buffer_descriptor_list_max_entries; 276 277 return {}; 278} 279 280ErrorOr<NonnullOwnPtr<AC97::AC97Channel>> AC97::AC97Channel::create_with_parent_pci_device(PCI::Address pci_device_address, StringView name, NonnullOwnPtr<IOWindow> channel_io_base) 281{ 282 return adopt_nonnull_own_or_enomem(new (nothrow) AC97::AC97Channel(pci_device_address, name, move(channel_io_base))); 283} 284 285void AC97::AC97Channel::handle_dma_stopped() 286{ 287 dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: DMA engine has stopped", m_device_pci_address, name()); 288 m_dma_running.with([this](auto& dma_running) { 289 // NOTE: QEMU might send spurious interrupts while we're not running, so we don't want to panic here. 290 if (!dma_running) 291 dbgln("AC97 @ {}: received DMA interrupt while it wasn't running", m_device_pci_address); 292 dma_running = false; 293 }); 294} 295 296void AC97::AC97Channel::reset() 297{ 298 dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: resetting", m_device_pci_address, name()); 299 300 m_channel_io_window->write8(Register::Control, AudioControlRegisterFlag::ResetRegisters); 301 302 while ((m_channel_io_window->read8(Register::Control) & AudioControlRegisterFlag::ResetRegisters) > 0) 303 microseconds_delay(50); 304 305 m_dma_running.with([](auto& dma_running) { 306 dma_running = false; 307 }); 308} 309 310void AC97::AC97Channel::set_last_valid_index(u32 buffer_address, u8 last_valid_index) 311{ 312 dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: setting buffer address: {:#x} LVI: {}", m_device_pci_address, name(), buffer_address, last_valid_index); 313 314 m_channel_io_window->write32(Register::BufferDescriptorListBaseAddress, buffer_address); 315 m_channel_io_window->write8(Register::LastValidIndex, last_valid_index); 316} 317 318void AC97::AC97Channel::start_dma() 319{ 320 dbgln_if(AC97_DEBUG, "AC97 @ {}: channel {}: starting DMA engine", m_device_pci_address, name()); 321 322 auto control = m_channel_io_window->read8(Register::Control); 323 control |= AudioControlRegisterFlag::RunPauseBusMaster; 324 control |= AudioControlRegisterFlag::FIFOErrorInterruptEnable; 325 control |= AudioControlRegisterFlag::InterruptOnCompletionEnable; 326 m_channel_io_window->write8(Register::Control, control); 327 328 m_dma_running.with([](auto& dma_running) { 329 dma_running = true; 330 }); 331} 332 333}