1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <fbl/intrusive_double_list.h> 8#include <fbl/ref_ptr.h> 9#include <fbl/slab_allocator.h> 10 11#include <intel-hda/codec-utils/stream-base.h> 12#include <intel-hda/utils/codec-caps.h> 13 14#include "utils.h" 15 16namespace audio { 17namespace intel_hda { 18namespace codecs { 19 20#define DECLARE_THUNK(_name) \ 21 zx_status_t _name(const Command& cmd, const CodecResponse& resp) __TA_REQUIRES(obj_lock()); 22 23class RealtekStream : public IntelHDAStreamBase { 24public: 25 RealtekStream(const StreamProperties& props); 26 27protected: 28 friend class fbl::RefPtr<RealtekStream>; 29 30 virtual ~RealtekStream() { } 31 32 // IntelHDAStreamBase implementation 33 zx_status_t OnActivateLocked() __TA_REQUIRES(obj_lock()) final; 34 void OnDeactivateLocked() __TA_REQUIRES(obj_lock()) final; 35 void OnChannelDeactivateLocked(const dispatcher::Channel& channel) 36 __TA_REQUIRES(obj_lock()) final; 37 zx_status_t OnDMAAssignedLocked() __TA_REQUIRES(obj_lock()) final; 38 zx_status_t OnSolicitedResponseLocked(const CodecResponse& resp) 39 __TA_REQUIRES(obj_lock()) final; 40 zx_status_t OnUnsolicitedResponseLocked(const CodecResponse& resp) 41 __TA_REQUIRES(obj_lock()) final; 42 zx_status_t BeginChangeStreamFormatLocked(const audio_proto::StreamSetFmtReq& fmt) 43 __TA_REQUIRES(obj_lock()) final; 44 zx_status_t FinishChangeStreamFormatLocked(uint16_t encoded_fmt) 45 __TA_REQUIRES(obj_lock()) final; 46 void OnGetGainLocked(audio_proto::GetGainResp* out_resp) __TA_REQUIRES(obj_lock()) final; 47 void OnSetGainLocked(const audio_proto::SetGainReq& req, 48 audio_proto::SetGainResp* out_resp) __TA_REQUIRES(obj_lock()) final; 49 void OnPlugDetectLocked(dispatcher::Channel* response_channel, 50 const audio_proto::PlugDetectReq& req, 51 audio_proto::PlugDetectResp* out_resp) __TA_REQUIRES(obj_lock()) final; 52 void OnGetStringLocked(const audio_proto::GetStringReq& req, 53 audio_proto::GetStringResp* out_resp) __TA_REQUIRES(obj_lock()) final; 54 55private: 56 struct Command { 57 using Thunk = zx_status_t (RealtekStream::*)(const Command& cmd, 58 const CodecResponse& resp); 59 const uint16_t nid; 60 const CodecVerb verb; 61 const Thunk thunk = nullptr; 62 }; 63 64 // Capabilities common to both converters and pin complexes. 65 struct CommonCaps { 66 AudioWidgetCaps widget_caps; 67 AmpCaps amp_caps; 68 bool has_amp = false; 69 float max_gain = 0.0; 70 float min_gain = 0.0; 71 float gain_step = 0.0; 72 }; 73 74 // Capabilities for converters 75 struct ConverterCaps : public CommonCaps { 76 SampleCaps sample_caps; 77 }; 78 79 // Capabilities for pin complexes 80 struct PinComplexCaps : public CommonCaps { 81 ConfigDefaults cfg_defaults; 82 PinCaps pin_caps; 83 bool async_plug_det = false; 84 uint8_t unsol_tag; 85 }; 86 87 // Declare a slab allocator for PendingCommands. Note; it needs to be made 88 // our friend in order to see the definition of the PendingCommand private 89 // inner class. 90 class PendingCommand; 91 using PCAT = fbl::StaticSlabAllocatorTraits<fbl::unique_ptr<PendingCommand>, 4096>; 92 using PendingCommandAllocator = fbl::SlabAllocator<PCAT>; 93 friend PendingCommandAllocator; 94 95 class PendingCommand : public fbl::DoublyLinkedListable<fbl::unique_ptr<PendingCommand>>, 96 public fbl::SlabAllocated<PCAT> { 97 public: 98 const Command& cmd() const { return cmd_; } 99 100 zx_status_t Invoke(RealtekStream* stream, 101 const CodecResponse& resp) __TA_REQUIRES(stream->obj_lock()) { 102 ZX_DEBUG_ASSERT((stream != nullptr) && (cmd_.thunk != nullptr)); 103 return ((*stream).*(cmd_.thunk))(cmd_, resp); 104 } 105 106 private: 107 // Hide our constructor and make the allocator our friend so that people 108 // do not accidentally allocate a pending command using std::new 109 friend PendingCommandAllocator; 110 PendingCommand(const Command& cmd) : cmd_(cmd) { } 111 Command cmd_; 112 }; 113 114 // TODO(johngro) : Elminiate this complexity if/when we get to the point 115 // that audio streams have a 1:1 relationship with their clients (instead of 116 // 1:many) 117 struct NotifyTarget : fbl::DoublyLinkedListable<fbl::unique_ptr<NotifyTarget>> { 118 explicit NotifyTarget(fbl::RefPtr<dispatcher::Channel>&& ch) : channel(ch) { } 119 fbl::RefPtr<dispatcher::Channel> channel; 120 }; 121 using NotifyTargetList = fbl::DoublyLinkedList<fbl::unique_ptr<NotifyTarget>>; 122 123 // Bits used to track setup state machine progress. 124 static constexpr uint32_t PIN_COMPLEX_SETUP_COMPLETE = (1u << 0); 125 static constexpr uint32_t CONVERTER_SETUP_COMPLETE = (1u << 1); 126 static constexpr uint32_t PLUG_STATE_SETUP_COMPLETE = (1u << 2); 127 static constexpr uint32_t DMA_ASSIGNMENT_COMPLETE = (1u << 3); 128 static constexpr uint32_t STREAM_PUBLISHED = (1u << 31); 129 static constexpr uint32_t ALL_SETUP_COMPLETE = PIN_COMPLEX_SETUP_COMPLETE 130 | CONVERTER_SETUP_COMPLETE 131 | PLUG_STATE_SETUP_COMPLETE 132 | DMA_ASSIGNMENT_COMPLETE; 133 134 static uint8_t ComputeGainSteps(const CommonCaps& caps, float target_gai); 135 136 zx_status_t RunCmdLocked(const Command& cmd) 137 __TA_REQUIRES(obj_lock()); 138 139 zx_status_t RunCmdListLocked(const Command* list, size_t count, bool force_all = false) 140 __TA_REQUIRES(obj_lock()); 141 142 zx_status_t DisableConverterLocked(bool force_all = false) __TA_REQUIRES(obj_lock()); 143 zx_status_t UpdateConverterGainLocked(float target_gain) __TA_REQUIRES(obj_lock()); 144 float ComputeCurrentGainLocked() __TA_REQUIRES(obj_lock()); 145 zx_status_t SendGainUpdatesLocked() __TA_REQUIRES(obj_lock()); 146 void AddPDNotificationTgtLocked(dispatcher::Channel* channel) __TA_REQUIRES(obj_lock()); 147 void RemovePDNotificationTgtLocked(const dispatcher::Channel& channel) 148 __TA_REQUIRES(obj_lock()); 149 150 // Setup state machine methods. 151 zx_status_t UpdateSetupProgressLocked(uint32_t stage) __TA_REQUIRES(obj_lock()); 152 zx_status_t FinalizeSetupLocked() __TA_REQUIRES(obj_lock()); 153 void DumpStreamPublishedLocked() __TA_REQUIRES(obj_lock()); 154 void DumpAmpCaps(const CommonCaps& caps, const char* tag); 155 DECLARE_THUNK(ProcessPinWidgetCaps); 156 DECLARE_THUNK(ProcessPinAmpCaps); 157 DECLARE_THUNK(ProcessPinCfgDefaults); 158 DECLARE_THUNK(ProcessPinCaps); 159 DECLARE_THUNK(ProcessPinState); 160 DECLARE_THUNK(ProcessConverterWidgetCaps); 161 DECLARE_THUNK(ProcessConverterAmpCaps); 162 DECLARE_THUNK(ProcessConverterSampleSizeRate); 163 DECLARE_THUNK(ProcessConverterSampleFormats); 164 165 bool can_mute() const __TA_REQUIRES(obj_lock()) { 166 return (conv_.has_amp && conv_.amp_caps.can_mute()) || 167 (pc_.has_amp && pc_.amp_caps.can_mute()); 168 } 169 170 const StreamProperties props_; 171 fbl::DoublyLinkedList<fbl::unique_ptr<PendingCommand>> pending_cmds_ __TA_GUARDED(obj_lock()); 172 173 // Setup state machine progress. 174 uint32_t setup_progress_ __TA_GUARDED(obj_lock()) = 0; 175 bool format_set_ __TA_GUARDED(obj_lock()) = false; 176 177 // Current gain and plug detect settings. 178 uint8_t cur_conv_gain_steps_ __TA_GUARDED(obj_lock()) = 0; 179 uint8_t cur_pc_gain_steps_ __TA_GUARDED(obj_lock()) = 0; 180 bool cur_mute_ __TA_GUARDED(obj_lock()) = false; 181 bool plug_state_ __TA_GUARDED(obj_lock()) = true; 182 zx_time_t last_plug_time_ __TA_GUARDED(obj_lock()) = 0; 183 NotifyTargetList plug_notify_targets_ __TA_GUARDED(obj_lock()); 184 185 // Converter and pin complex capabilities. 186 ConverterCaps conv_ __TA_GUARDED(obj_lock()); 187 PinComplexCaps pc_ __TA_GUARDED(obj_lock()); 188}; 189 190#undef DECLARE_THUNK 191 192} // namespace codecs 193} // namespace intel_hda 194} // namespace audio 195 196// TODO(johngro) : Right now, there is no really good way to hide a static slab 197// allocator from the rest of the world. It is not really much of a concern 198// here, but it seems odd to have a private inner class which can be 199// instantiated by things outside of the class. 200// 201// We should probably either fix static slab allocators so that they can be made 202// private inner classes as well, or just go ahead and make these slab allocated 203// bookkeeping classes non-inner-classes. 204FWD_DECL_STATIC_SLAB_ALLOCATOR(audio::intel_hda::codecs::RealtekStream::PCAT); 205 206