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 #include <limits>
6 #include <dirent.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 
10 #include <zircon/device/intel-hda.h>
11 #include <lib/fdio/io.h>
12 
13 #include "zircon_device.h"
14 
15 namespace audio {
16 namespace intel_hda {
17 
18 uint32_t ZirconDevice::transaction_id_ = 0;
19 
Connect()20 zx_status_t ZirconDevice::Connect() {
21     if (dev_channel_ != ZX_HANDLE_INVALID)
22         return ZX_OK;
23 
24     if (!dev_name_)
25         return ZX_ERR_NO_MEMORY;
26 
27     int fd = ::open(dev_name_, O_RDONLY);
28     if (fd < 0)
29         return static_cast<zx_status_t>(fd);
30 
31     ssize_t res = ::fdio_ioctl(fd, IHDA_IOCTL_GET_CHANNEL,
32                                nullptr, 0,
33                                &dev_channel_, sizeof(dev_channel_));
34     ::close(fd);
35 
36     if (res < 0) {
37         printf("[%s] Failed to fetch device channel (%zd)\n", dev_name(), res);
38         return static_cast<zx_status_t>(res);
39     }
40 
41     return ZX_OK;
42 }
43 
Disconnect()44 void ZirconDevice::Disconnect() {
45     if (dev_channel_ != ZX_HANDLE_INVALID) {
46         ::zx_handle_close(dev_channel_);
47         dev_channel_ = ZX_HANDLE_INVALID;
48     }
49 }
50 
CallDevice(const zx_channel_call_args_t & args,uint64_t timeout_msec)51 zx_status_t ZirconDevice::CallDevice(const zx_channel_call_args_t& args, uint64_t timeout_msec) {
52     uint32_t resp_size;
53     uint32_t resp_handles;
54     zx_time_t deadline;
55 
56     if (timeout_msec == ZX_TIME_INFINITE) {
57         deadline = ZX_TIME_INFINITE;
58     } else if (timeout_msec >= std::numeric_limits<zx_time_t>::max() / ZX_MSEC(1)) {
59         return ZX_ERR_INVALID_ARGS;
60     } else {
61         deadline = zx_deadline_after(ZX_MSEC(timeout_msec));
62     }
63 
64     return zx_channel_call(dev_channel_, 0, deadline, &args, &resp_size, &resp_handles);
65 }
66 
Enumerate(void * ctx,const char * const dev_path,EnumerateCbk cbk)67 zx_status_t ZirconDevice::Enumerate(
68         void* ctx,
69         const char* const dev_path,
70         EnumerateCbk cbk) {
71     static constexpr size_t FILENAME_SIZE = 256;
72 
73     struct dirent* de;
74     DIR* dir = opendir(dev_path);
75     zx_status_t res = ZX_OK;
76     char buf[FILENAME_SIZE];
77 
78     if (!dir)
79         return ZX_ERR_NOT_FOUND;
80 
81     while ((de = readdir(dir)) != NULL) {
82         uint32_t id;
83         if (sscanf(de->d_name, "%u", &id) == 1) {
84             size_t total = 0;
85 
86             total += snprintf(buf + total, sizeof(buf) - total, "%s/", dev_path);
87             total += snprintf(buf + total, sizeof(buf) - total, "%03u", id);
88 
89             res = cbk(ctx, id, buf);
90             if (res != ZX_OK)
91                 goto done;
92         }
93     }
94 
95 done:
96     closedir(dir);
97     return res;
98 }
99 
100 }  // namespace audio
101 }  // namespace intel_hda
102