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 
15 namespace audio {
16 namespace intel_hda {
17 
18 class ZirconDevice {
19 public:
20     zx_status_t Connect();
21     void Disconnect();
22 
dev_name()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 
30 protected:
ZirconDevice(const char * const dev_name)31     explicit ZirconDevice(const char* const dev_name)
32         : dev_name_(::strdup(dev_name)) { }
33 
~ZirconDevice()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>
InitRequest(ReqType * req,ihda_cmd_t cmd)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 
73 private:
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