/* * Copyright (c) 2023, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include 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 stop(); ErrorOr 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 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 initialize_buffer(); ErrorOr reset(); NonnullOwnPtr m_stream_io_window; u8 m_stream_number; OwnPtr m_buffer_descriptor_list; SpinlockProtected, 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> create(NonnullOwnPtr stream_io_window, u8 stream_number) { return adopt_nonnull_own_or_enomem(new (nothrow) OutputStream(move(stream_io_window), stream_number)); } ErrorOr write(UserOrKernelBuffer const&, size_t); private: OutputStream(NonnullOwnPtr 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 }