blob: 002f8a81b0954bfdcc095f67afc7465d4be07449 [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 <zircon/types.h>
#include <zx/channel.h>
#include <zx/vmo.h>
#include <fbl/macros.h>
#include <fbl/ref_ptr.h>
#include <dispatcher-pool/dispatcher-channel.h>
namespace audio {
namespace intel_hda {
#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_
using WaitConditionFn = bool (*)(void*);
zx_status_t WaitCondition(zx_time_t timeout,
zx_time_t poll_interval,
WaitConditionFn cond,
void* cond_ctx);
// Utility method for determining the physical mapping of the pages committed
// underneath a VMO. Automatically coalesces adjacent pages and reports the
// addresses and lengths of contiguous regions.
//
// @param vmo_handle A handle to the VMO to get region info for.
// @param vmo_size The size of the region of the VMO to get info for (in bytes).
// @param regions_out a pointer to an array of VMORegion structures which will
// hold the result of the operation.
// @param num_regions_inout A pointer to an integer which holds the length of
// the regions_out array on input, and hold the number of populated
// elements of the array on output. Only valid on output if the return
// code is ZX_OK.
// @returns An zx_status_t indicating success or failure of the operation.
struct VMORegion;
zx_status_t GetVMORegionInfo(const zx::vmo& vmo,
uint64_t vmo_size,
VMORegion* regions_out,
uint32_t* num_regions_inout);
struct VMORegion {
zx_paddr_t phys_addr;
uint64_t size;
};
// Utility class for managing allocation and mapping of contiguous physical
// memory.
class ContigPhysMem {
public:
ContigPhysMem() = default;
~ContigPhysMem() { Release(); }
DISALLOW_COPY_ASSIGN_AND_MOVE(ContigPhysMem);
// Allocate at least size bytes of contiguous physical memory. Allocatation
// will round up to the nearest page size.
zx_status_t Allocate(size_t size);
// Map a successfully allocated buffer into this address space with
// read/write permissions.
//
// TODO(johngro) : Should we provide control of permissions and cache policy
// here?
zx_status_t Map();
// If mapped, unmap. Then, if allocated, deallocate.
void Release();
zx_paddr_t phys() const { return phys_; }
uintptr_t virt() const { return virt_; }
size_t size() const { return size_; }
size_t actual_size() const { return actual_size_; }
private:
zx::vmo vmo_;
zx_paddr_t phys_ = 0;
uintptr_t virt_ = 0;
size_t size_ = 0;
size_t actual_size_ = 0;
};
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