blob: 99cd37ee85bf3728e6661cb7bc3ff4cc815bdf9f [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.
#pragma once
#include <ddk/device.h>
#include <fbl/macros.h>
#include <fbl/ref_ptr.h>
#include <limits.h>
#include <lib/fzl/vmar-manager.h>
#include <lib/zx/bti.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmo.h>
#include <zircon/types.h>
#include <dispatcher-pool/dispatcher-channel.h>
namespace audio {
namespace intel_hda {
// Constants
// HDA controllers can have at most 30 stream contexts.
constexpr size_t MAX_STREAMS_PER_CONTROLLER = 30;
// CORB/RIRB should take no more than a page
constexpr size_t MAPPED_CORB_RIRB_SIZE = PAGE_SIZE;
// Individual BDLs should be 1 page each
constexpr size_t MAPPED_BDL_SIZE = PAGE_SIZE;
#define _SIC_ static inline constexpr
template <typename T> _SIC_ T OR(T x, T y) { return static_cast<T>(x | y); }
template <typename T> _SIC_ T AND(T x, T y) { return static_cast<T>(x & y); }
#undef _SIC_
// Static container for the driver wide VMARs that we stash all of our register
// mappings in, in order to make efficient use of kernel PTEs
class DriverVmars {
public:
static zx_status_t Initialize();
static void Shutdown();
static const fbl::RefPtr<fzl::VmarManager>& registers() {
return registers_;
}
private:
static fbl::RefPtr<fzl::VmarManager> registers_;
};
struct StreamFormat {
// Stream format bitfields documented in section 3.7.1
static constexpr uint16_t FLAG_NON_PCM = (1u << 15);
constexpr StreamFormat() { }
explicit constexpr StreamFormat(uint16_t raw_data) : raw_data_(raw_data) { }
uint32_t BASE() const { return (raw_data_ & (1u << 14)) ? 44100 : 48000; }
uint32_t CHAN() const { return (raw_data_ & 0xF) + 1; }
uint32_t DIV() const { return ((raw_data_ >> 8) & 0x7) + 1; }
uint32_t MULT() const {
uint32_t bits = (raw_data_ >> 11) & 0x7;
if (bits >= 4)
return 0;
return bits + 1;
}
uint32_t BITS_NDX() const { return (raw_data_ >> 4) & 0x7; }
uint32_t BITS() const {
switch (BITS_NDX()) {
case 0: return 8u;
case 1: return 16u;
case 2: return 20u;
case 3: return 24u;
case 4: return 32u;
default: return 0u;
}
}
bool is_pcm() const { return (raw_data_ & FLAG_NON_PCM) == 0; }
uint32_t sample_rate() const { return (BASE() * MULT()) / DIV(); }
uint32_t channels() const { return CHAN(); }
uint32_t bits_per_chan() const { return BITS(); }
uint32_t bytes_per_frame() const {
uint32_t ret = CHAN();
switch (BITS_NDX()) {
case 0: return ret;
case 1: return ret << 1;
case 2:
case 3:
case 4: return ret << 2;
default: return 0u;
}
}
bool SanityCheck() const {
if (raw_data_ == 0x8000)
return true;
if (raw_data_ & 0x8080)
return false;
return (BITS() && MULT());
}
uint16_t raw_data_ = 0;
};
// Boilerplate code to handle an IOCTL request to create a channel from an
// application. Assuming that the request passes all of the sanity checks,
// attempts to create a channel and bind it to this owner using the supplied
// dispatching behavior, then send the other end of the channel back to the
// application.
zx_status_t HandleDeviceIoctl(uint32_t op,
void* out_buf,
size_t out_len,
size_t* out_actual,
const fbl::RefPtr<dispatcher::ExecutionDomain>& domain,
dispatcher::Channel::ProcessHandler phandler,
dispatcher::Channel::ChannelClosedHandler chandler);
// Attempts to create and activate a channel using the supplied dispatcher
// bindings and binding it to this ExeuctionDomain in the process. Callers must
// take ownership of the remote channel endpoint, but may choose to ignore the
// local channel endpoint by passing nullptr for local_endpoint_out. Upon
// success, a reference to the created dispatcher::Channel will be held by the
// channel's ExeuctionDomain (as a result of the activation operation)
zx_status_t CreateAndActivateChannel(const fbl::RefPtr<dispatcher::ExecutionDomain>& domain,
dispatcher::Channel::ProcessHandler phandler,
dispatcher::Channel::ChannelClosedHandler chandler,
fbl::RefPtr<dispatcher::Channel>* local_endpoint_out,
zx::channel* remote_endpoint_out);
} // namespace intel_hda
} // namespace audio