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 <zircon/assert.h>
8#include <zircon/device/intel-hda.h>
9#include <zircon/syscalls.h>
10#include <zircon/types.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15namespace audio {
16namespace intel_hda {
17
18class ZirconDevice {
19public:
20    zx_status_t Connect();
21    void Disconnect();
22
23    const char* dev_name() const { return dev_name_ ? dev_name_ : "<unknown>"; }
24
25    using EnumerateCbk = zx_status_t (*)(void* ctx, uint32_t id, const char* const str);
26    static zx_status_t Enumerate(void* ctx,
27                                 const char* const dev_path,
28                                 EnumerateCbk cbk);
29
30protected:
31    explicit ZirconDevice(const char* const dev_name)
32        : dev_name_(::strdup(dev_name)) { }
33
34    ~ZirconDevice() {
35        Disconnect();
36        if (dev_name_) ::free(dev_name_);
37    }
38
39    template <typename ReqType, typename RespType>
40    zx_status_t CallDevice(const ReqType& req, RespType* resp, uint64_t timeout_msec = 100) {
41        if (!resp)
42            return ZX_ERR_INVALID_ARGS;
43
44        zx_status_t res = Connect();
45        if (res != ZX_OK)
46            return res;
47
48        zx_channel_call_args_t args;
49        memset(&args, 0, sizeof(args));
50
51        // TODO(johngro) : get rid of this const cast
52        args.wr_bytes     = const_cast<ReqType*>(&req);
53        args.wr_num_bytes = sizeof(req);
54        args.rd_bytes     = resp;
55        args.rd_num_bytes = sizeof(*resp);
56
57        return CallDevice(args, timeout_msec);
58    }
59
60    template <typename ReqType>
61    static void InitRequest(ReqType* req, ihda_cmd_t cmd) {
62        ZX_DEBUG_ASSERT(req != nullptr);
63        memset(req, 0, sizeof(*req));
64        do {
65            req->hdr.transaction_id = ++transaction_id_;
66        } while (req->hdr.transaction_id == IHDA_INVALID_TRANSACTION_ID);
67        req->hdr.cmd = cmd;
68    }
69
70    char* dev_name_;
71    zx_handle_t dev_channel_ = ZX_HANDLE_INVALID;
72
73private:
74    zx_status_t CallDevice(const zx_channel_call_args_t& args, uint64_t timeout_msec);
75    static uint32_t transaction_id_;
76};
77
78}  // namespace audio
79}  // namespace intel_hda
80