diff options
Diffstat (limited to 'Kernel/Devices/Audio/IntelHDA/Stream.h')
-rw-r--r-- | Kernel/Devices/Audio/IntelHDA/Stream.h | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/Kernel/Devices/Audio/IntelHDA/Stream.h b/Kernel/Devices/Audio/IntelHDA/Stream.h new file mode 100644 index 0000000000..eb61165a19 --- /dev/null +++ b/Kernel/Devices/Audio/IntelHDA/Stream.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023, Jelle Raaijmakers <jelle@gmta.nl> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Error.h> +#include <AK/NonnullOwnPtr.h> +#include <AK/OwnPtr.h> +#include <Kernel/Devices/Audio/IntelHDA/Codec.h> +#include <Kernel/Devices/Audio/IntelHDA/Format.h> +#include <Kernel/IOWindow.h> +#include <Kernel/Locking/SpinlockProtected.h> + +namespace Kernel::Audio::IntelHDA { + +class Stream { +public: + static constexpr u32 cyclic_buffer_size_in_ms = 40; + + u8 stream_number() const { return m_stream_number; } + bool running() const { return m_running; } + u32 sample_rate() const { return m_format_parameters.sample_rate; } + + void start(); + ErrorOr<void> stop(); + + ErrorOr<void> set_format(FormatParameters); + +protected: + // We always need 2 filled buffers, plus an additional one to prevent buffer underrun + static constexpr u8 minimum_number_of_buffers = 3; + + // 3.3: High Definition Audio Controller Register Set - streams + enum StreamRegisterOffset : u8 { + Control = 0x00, + Status = 0x03, + LinkPosition = 0x04, + CyclicBufferLength = 0x08, + LastValidIndex = 0x0c, + Format = 0x12, + BDLLowerBaseAddress = 0x18, + BDLUpperBaseAddress = 0x1c, + }; + + // 3.3.35: Input/Output/Bidirectional Stream Descriptor Control + enum StreamControlFlag : u32 { + StreamReset = 1u << 0, + StreamRun = 1u << 1, + }; + + Stream(NonnullOwnPtr<IOWindow> stream_io_window, u8 stream_number) + : m_stream_io_window(move(stream_io_window)) + , m_stream_number(stream_number) + { + } + + ~Stream(); + + u32 read_control(); + void write_control(u32); + + ErrorOr<void> initialize_buffer(); + ErrorOr<void> reset(); + + NonnullOwnPtr<IOWindow> m_stream_io_window; + u8 m_stream_number; + OwnPtr<Memory::Region> m_buffer_descriptor_list; + SpinlockProtected<OwnPtr<Memory::Region>, LockRank::None> m_buffers; + size_t m_buffer_position { 0 }; + bool m_running { false }; + FormatParameters m_format_parameters; +}; + +class OutputStream : public Stream { +public: + static constexpr u8 fixed_channel = 0; + + static ErrorOr<NonnullOwnPtr<OutputStream>> create(NonnullOwnPtr<IOWindow> stream_io_window, u8 stream_number) + { + return adopt_nonnull_own_or_enomem(new (nothrow) OutputStream(move(stream_io_window), stream_number)); + } + + ErrorOr<size_t> write(UserOrKernelBuffer const&, size_t); + +private: + OutputStream(NonnullOwnPtr<IOWindow> stream_io_window, u8 stream_number) + : Stream(move(stream_io_window), stream_number) + { + // 3.3.35: Input/Output/Bidirectional Stream Descriptor Control + // "Although the controller hardware is capable of transmitting any stream number, + // by convention stream 0 is reserved as unused by software, so that converters + // whose stream numbers have been reset to 0 do not unintentionally decode data + // not intended for them." + VERIFY(stream_number >= 1); + } +}; + +// FIXME: implement InputStream and BidirectionalStream + +} |