| // 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 |