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 <ddk/binding.h> 8#include <ddk/device.h> 9#include <ddk/protocol/intel-hda-codec.h> 10#include <lib/zx/handle.h> 11#include <fbl/mutex.h> 12#include <fbl/ref_counted.h> 13#include <fbl/ref_ptr.h> 14#include <fbl/unique_ptr.h> 15#include <stdint.h> 16#include <string.h> 17#include <zircon/thread_annotations.h> 18 19#include <dispatcher-pool/dispatcher-channel.h> 20#include <dispatcher-pool/dispatcher-execution-domain.h> 21#include <intel-hda/utils/codec-commands.h> 22#include <intel-hda/utils/intel-hda-proto.h> 23#include <intel-hda/utils/intel-hda-registers.h> 24 25#include "codec-cmd-job.h" 26#include "debug-logging.h" 27#include "intel-hda-stream.h" 28 29namespace audio { 30namespace intel_hda { 31 32class IntelHDAController; 33struct CodecResponse; 34 35class IntelHDACodec : public fbl::RefCounted<IntelHDACodec> { 36public: 37 enum class State { 38 PROBING, 39 FINDING_DRIVER, 40 OPERATING, 41 SHUTTING_DOWN, 42 SHUT_DOWN, 43 FATAL_ERROR, 44 }; 45 46 static fbl::RefPtr<IntelHDACodec> Create(IntelHDAController& controller, uint8_t codec_id); 47 48 zx_status_t Startup(); 49 void ProcessSolicitedResponse(const CodecResponse& resp, fbl::unique_ptr<CodecCmdJob>&& job); 50 void ProcessUnsolicitedResponse(const CodecResponse& resp); 51 void ProcessWakeupEvt(); 52 53 // TODO (johngro) : figure out shutdown... Currently, this expected to 54 // execute synchronously, which does not allow codec drivers any opportunity 55 // to perform a graceful shutdown. 56 // 57 // OTOH - If our driver is being unloaded by the device manager, in theory, 58 // it should have already unloaded all of the codecs, giving them a chances 59 // to quiesce their hardware in the process. 60 void Shutdown(); 61 62 uint8_t id() const { return codec_id_; } 63 State state() const { return state_; } 64 const char* log_prefix() const { return log_prefix_; } 65 66 // Debug/Diags 67 void DumpState(); 68 69private: 70 friend class fbl::RefPtr<IntelHDACodec>; 71 72 using ProbeParseCbk = zx_status_t (IntelHDACodec::*)(const CodecResponse& resp); 73 struct ProbeCommandListEntry { 74 CodecVerb verb; 75 ProbeParseCbk parse; 76 }; 77 78 static constexpr size_t PROP_PROTOCOL = 0; 79 static constexpr size_t PROP_VID = 1; 80 static constexpr size_t PROP_DID = 2; 81 static constexpr size_t PROP_MAJOR_REV = 3; 82 static constexpr size_t PROP_MINOR_REV = 4; 83 static constexpr size_t PROP_VENDOR_REV = 5; 84 static constexpr size_t PROP_VENDOR_STEP = 6; 85 static constexpr size_t PROP_COUNT = 7; 86 87 static zx_protocol_device_t CODEC_DEVICE_THUNKS; 88 static ihda_codec_protocol_ops_t CODEC_PROTO_THUNKS; 89 90 IntelHDACodec(IntelHDAController& controller, uint8_t codec_id); 91 virtual ~IntelHDACodec() { ZX_DEBUG_ASSERT(state_ == State::SHUT_DOWN); } 92 93 zx_status_t PublishDevice(); 94 95 void SendCORBResponse(const fbl::RefPtr<dispatcher::Channel>& channel, 96 const CodecResponse& resp, 97 uint32_t transaction_id = IHDA_INVALID_TRANSACTION_ID); 98 99 // Parsers for device probing 100 zx_status_t ParseVidDid(const CodecResponse& resp); 101 zx_status_t ParseRevisionId(const CodecResponse& resp); 102 103 // ZX_PROTOCOL_IHDA_CODEC Interface 104 zx_status_t CodecGetDispatcherChannel(zx_handle_t* channel_out); 105 106 // Thunks for interacting with clients and codec drivers. 107 zx_status_t DeviceIoctl(uint32_t op, void* out_buf, size_t out_len, size_t* out_actual); 108 zx_status_t ProcessClientRequest(dispatcher::Channel* channel, bool is_driver_channel); 109 void ProcessClientDeactivate(const dispatcher::Channel* channel); 110 zx_status_t ProcessGetIDs(dispatcher::Channel* channel, const ihda_proto::GetIDsReq& req); 111 zx_status_t ProcessSendCORBCmd(dispatcher::Channel* channel, 112 const ihda_proto::SendCORBCmdReq& req); 113 zx_status_t ProcessRequestStream(dispatcher::Channel* channel, 114 const ihda_proto::RequestStreamReq& req); 115 zx_status_t ProcessReleaseStream(dispatcher::Channel* channel, 116 const ihda_proto::ReleaseStreamReq& req); 117 zx_status_t ProcessSetStreamFmt(dispatcher::Channel* channel, 118 const ihda_proto::SetStreamFmtReq& req); 119 120 // Reference to our owner. 121 IntelHDAController& controller_; 122 123 // State management. 124 State state_ = State::PROBING; 125 uint probe_rx_ndx_ = 0; 126 127 // Driver connection state 128 fbl::Mutex codec_driver_channel_lock_; 129 fbl::RefPtr<dispatcher::Channel> codec_driver_channel_ TA_GUARDED(codec_driver_channel_lock_); 130 131 // Device properties. 132 const uint8_t codec_id_; 133 zx_device_prop_t dev_props_[PROP_COUNT]; 134 zx_device_t* dev_node_ = nullptr; 135 struct { 136 uint16_t vid; 137 uint16_t did; 138 uint8_t ihda_vmaj; 139 uint8_t ihda_vmin; 140 uint8_t rev_id; 141 uint8_t step_id; 142 } props_; 143 144 // Log prefix storage 145 char log_prefix_[LOG_PREFIX_STORAGE] = { 0 }; 146 147 // Dispatcher framework state. 148 fbl::RefPtr<dispatcher::ExecutionDomain> default_domain_; 149 150 // Active DMA streams 151 fbl::Mutex active_streams_lock_; 152 IntelHDAStream::Tree active_streams_ TA_GUARDED(active_streams_lock_); 153 154 static ProbeCommandListEntry PROBE_COMMANDS[]; 155}; 156 157} // namespace intel_hda 158} // namespace audio 159