blob: 40a3ca46d16601914b5b9a13e5bae0d9ee986b2b [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INTEL_HDA_CODEC_UTILS_STREAM_BASE_H_
#define INTEL_HDA_CODEC_UTILS_STREAM_BASE_H_
#include <fuchsia/hardware/audio/llcpp/fidl.h>
#include <lib/zx/channel.h>
#include <utility>
#include <audio-proto/audio-proto.h>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/protocol/intelhda/codec.h>
#include <ddktl/fidl.h>
#include <dispatcher-pool/dispatcher-channel.h>
#include <dispatcher-pool/dispatcher-execution-domain.h>
#include <fbl/intrusive_wavl_tree.h>
#include <fbl/mutex.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <fbl/vector.h>
#include <intel-hda/utils/codec-commands.h>
#include <intel-hda/utils/intel-hda-proto.h>
namespace audio {
namespace intel_hda {
namespace codecs {
class IntelHDACodecDriverBase;
class IntelHDAStreamBase : public fbl::RefCounted<IntelHDAStreamBase>,
public fbl::WAVLTreeContainable<fbl::RefPtr<IntelHDAStreamBase>>,
public ::llcpp::fuchsia::hardware::audio::Device::Interface {
public:
zx_status_t Activate(fbl::RefPtr<IntelHDACodecDriverBase>&& parent_codec,
const fbl::RefPtr<dispatcher::Channel>& codec_channel)
__TA_EXCLUDES(obj_lock_);
void Deactivate() __TA_EXCLUDES(obj_lock_, default_domain_->token());
zx_status_t ProcessResponse(const CodecResponse& resp) __TA_EXCLUDES(obj_lock_);
zx_status_t ProcessRequestStream(const ihda_proto::RequestStreamResp& resp)
__TA_EXCLUDES(obj_lock_);
virtual zx_status_t ProcessSetStreamFmt(const ihda_proto::SetStreamFmtResp& resp,
zx::channel&& ring_buffer_channel)
__TA_EXCLUDES(obj_lock_);
uint32_t id() const { return id_; }
bool is_input() const { return is_input_; }
uint32_t GetKey() const { return id(); }
protected:
friend class fbl::RefPtr<IntelHDAStreamBase>;
enum class Ack {
NO,
YES,
};
IntelHDAStreamBase(uint32_t id, bool is_input);
virtual ~IntelHDAStreamBase();
void SetPersistentUniqueId(const audio_stream_unique_id_t& id) __TA_EXCLUDES(obj_lock_);
// Properties available to subclasses.
uint8_t dma_stream_tag() const __TA_REQUIRES(obj_lock_) { return dma_stream_tag_; }
const fbl::RefPtr<IntelHDACodecDriverBase>& parent_codec() const __TA_REQUIRES(obj_lock_) {
return parent_codec_;
}
bool is_active() const __TA_REQUIRES(obj_lock_) { return parent_codec() != nullptr; }
fbl::Mutex* obj_lock() __TA_RETURN_CAPABILITY(obj_lock_) { return &obj_lock_; }
fbl::RefPtr<dispatcher::ExecutionDomain> domain() const { return default_domain_; }
fbl::RefPtr<dispatcher::Channel> stream_channel() const __TA_REQUIRES(obj_lock_) {
return stream_channel_;
}
uint32_t set_format_tid() const __TA_REQUIRES(obj_lock_) { return set_format_tid_; }
uint16_t encoded_fmt() const __TA_REQUIRES(obj_lock_) { return encoded_fmt_; }
// Methods callable from subclasses
zx_status_t PublishDeviceLocked() __TA_REQUIRES(obj_lock_);
void SetSupportedFormatsLocked(fbl::Vector<audio_proto::FormatRange>&& formats)
__TA_REQUIRES(obj_lock_) {
supported_formats_ = std::move(formats);
}
void SetFormatTidLocked(uint32_t set_format_tid) __TA_REQUIRES(obj_lock_) {
set_format_tid_ = set_format_tid;
}
// Overloads to control stream behavior.
virtual zx_status_t OnActivateLocked() __TA_REQUIRES(obj_lock_);
virtual void OnDeactivateLocked() __TA_REQUIRES(obj_lock_);
virtual void OnChannelDeactivateLocked(const dispatcher::Channel& channel)
__TA_REQUIRES(obj_lock_);
virtual zx_status_t OnDMAAssignedLocked() __TA_REQUIRES(obj_lock_);
virtual zx_status_t OnSolicitedResponseLocked(const CodecResponse& resp) __TA_REQUIRES(obj_lock_);
virtual zx_status_t OnUnsolicitedResponseLocked(const CodecResponse& resp)
__TA_REQUIRES(obj_lock_);
virtual zx_status_t BeginChangeStreamFormatLocked(const audio_proto::StreamSetFmtReq& fmt)
__TA_REQUIRES(obj_lock_);
virtual zx_status_t FinishChangeStreamFormatLocked(uint16_t encoded_fmt) __TA_REQUIRES(obj_lock_);
virtual void OnGetGainLocked(audio_proto::GetGainResp* out_resp) __TA_REQUIRES(obj_lock_);
virtual void OnSetGainLocked(const audio_proto::SetGainReq& req,
audio_proto::SetGainResp* out_resp) __TA_REQUIRES(obj_lock_);
virtual void OnPlugDetectLocked(dispatcher::Channel* response_channel,
const audio_proto::PlugDetectReq& req,
audio_proto::PlugDetectResp* out_resp) __TA_REQUIRES(obj_lock_);
virtual void OnGetStringLocked(const audio_proto::GetStringReq& req,
audio_proto::GetStringResp* out_resp) __TA_REQUIRES(obj_lock_);
virtual void OnGetClockDomainLocked(audio_proto::GetClockDomainResp* out_resp)
__TA_REQUIRES(obj_lock_);
// Debug logging
virtual void PrintDebugPrefix() const;
zx_status_t SendCodecCommandLocked(uint16_t nid, CodecVerb verb, Ack do_ack)
__TA_REQUIRES(obj_lock_);
zx_status_t SendCodecCommand(uint16_t nid, CodecVerb verb, Ack do_ack) __TA_EXCLUDES(obj_lock_) {
fbl::AutoLock obj_lock(&obj_lock_);
return SendCodecCommandLocked(nid, verb, do_ack);
}
// Exposed to derived class for thread annotations.
const fbl::Mutex& obj_lock() const __TA_RETURN_CAPABILITY(obj_lock_) { return obj_lock_; }
// Unsolicited tag allocation for streams.
zx_status_t AllocateUnsolTagLocked(uint8_t* out_tag) __TA_REQUIRES(obj_lock_);
void ReleaseUnsolTagLocked(uint8_t tag) __TA_REQUIRES(obj_lock_);
private:
// fuchsia.hardware.audio.Device
void GetChannel(GetChannelCompleter::Sync completer) override;
// Thunks for dispatching channel events.
zx_status_t ProcessClientRequest(dispatcher::Channel* channel, bool privileged);
void ProcessClientDeactivate(const dispatcher::Channel* channel, bool privileged);
zx_status_t DoGetStreamFormatsLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::StreamGetFmtsReq& req)
__TA_REQUIRES(obj_lock_);
zx_status_t DoSetStreamFormatLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::StreamSetFmtReq& fmt)
__TA_REQUIRES(obj_lock_);
zx_status_t DoGetGainLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::GetGainReq& req) __TA_REQUIRES(obj_lock_);
zx_status_t DoSetGainLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::SetGainReq& req) __TA_REQUIRES(obj_lock_);
zx_status_t DoPlugDetectLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::PlugDetectReq& req) __TA_REQUIRES(obj_lock_);
zx_status_t DoGetUniqueIdLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::GetUniqueIdReq& req) __TA_REQUIRES(obj_lock_);
zx_status_t DoGetStringLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::GetStringReq& req) __TA_REQUIRES(obj_lock_);
zx_status_t DoGetClockDomainLocked(dispatcher::Channel* channel, bool privileged,
const audio_proto::GetClockDomainReq& req)
__TA_REQUIRES(obj_lock_);
zx_status_t SetDMAStreamLocked(uint16_t id, uint8_t tag) __TA_REQUIRES(obj_lock_);
const uint32_t id_;
const bool is_input_;
char dev_name_[ZX_DEVICE_NAME_MAX] = {0};
fbl::Mutex obj_lock_;
fbl::RefPtr<IntelHDACodecDriverBase> parent_codec_ __TA_GUARDED(obj_lock_);
fbl::RefPtr<dispatcher::Channel> codec_channel_ __TA_GUARDED(obj_lock_);
fbl::RefPtr<dispatcher::ExecutionDomain> default_domain_;
uint16_t dma_stream_id_ __TA_GUARDED(obj_lock_) = IHDA_INVALID_STREAM_ID;
uint8_t dma_stream_tag_ __TA_GUARDED(obj_lock_) = IHDA_INVALID_STREAM_TAG;
zx_device_t* parent_device_ __TA_GUARDED(obj_lock_) = nullptr;
zx_device_t* stream_device_ __TA_GUARDED(obj_lock_) = nullptr;
fbl::RefPtr<dispatcher::Channel> stream_channel_ __TA_GUARDED(obj_lock_);
fbl::Vector<audio_proto::FormatRange> supported_formats_ __TA_GUARDED(obj_lock_);
uint32_t set_format_tid_ __TA_GUARDED(obj_lock_) = AUDIO_INVALID_TRANSACTION_ID;
uint16_t encoded_fmt_ __TA_GUARDED(obj_lock_);
uint32_t unsol_tag_count_ __TA_GUARDED(obj_lock_) = 0;
audio_stream_unique_id_t persistent_unique_id_;
static zx_status_t EncodeStreamFormat(const audio_proto::StreamSetFmtReq& fmt,
uint16_t* encoded_fmt_out);
static zx_protocol_device_t STREAM_DEVICE_THUNKS;
};
} // namespace codecs
} // namespace intel_hda
} // namespace audio
#endif // INTEL_HDA_CODEC_UTILS_STREAM_BASE_H_