1 // Copyright 2016 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 "lock.h"
8 #include "device-internal.h"
9 #include "../shared/async-loop-owned-rpc-handler.h"
10 
11 #include <ddk/binding.h>
12 #include <ddk/device.h>
13 #include <ddk/driver.h>
14 
15 #include <fbl/intrusive_double_list.h>
16 #include <fbl/ref_counted.h>
17 #include <fbl/ref_ptr.h>
18 #include <fbl/string.h>
19 #include <fbl/unique_ptr.h>
20 #include <lib/async/cpp/wait.h>
21 #include <lib/zx/channel.h>
22 #include <zircon/compiler.h>
23 #include <zircon/fidl.h>
24 #include <zircon/thread_annotations.h>
25 #include <zircon/types.h>
26 
27 #include <threads.h>
28 #include <stdint.h>
29 
30 namespace devmgr {
31 
32 struct CreationContext {
33     fbl::RefPtr<zx_device_t> parent;
34     fbl::RefPtr<zx_device_t> child;
35     zx::unowned_channel rpc;
36 };
37 
38 void devhost_set_creation_context(CreationContext* ctx);
39 
40 } // namespace devmgr
41 
42 // Nothing outside of devmgr/{devmgr,devhost,rpc-device}.c
43 // should be calling devhost_*() APIs, as this could
44 // violate the internal locking design.
45 
46 // Safe external APIs are in device.h and device_internal.h
47 
48 // Note that this must be a struct to match the public opaque declaration.
49 struct zx_driver : fbl::DoublyLinkedListable<fbl::RefPtr<zx_driver>>,
50                    fbl::RefCounted<zx_driver> {
51     static zx_status_t Create(fbl::RefPtr<zx_driver>* out_driver);
52 
namezx_driver53     const char* name() const {
54         return name_;
55     }
56 
driver_reczx_driver57     zx_driver_rec_t* driver_rec() const {
58         return driver_rec_;
59     }
60 
statuszx_driver61     zx_status_t status() const {
62         return status_;
63     }
64 
libnamezx_driver65     const fbl::String& libname() const {
66         return libname_;
67     }
68 
set_namezx_driver69     void set_name(const char* name) {
70         name_ = name;
71     }
72 
set_driver_reczx_driver73     void set_driver_rec(zx_driver_rec_t* driver_rec) {
74         driver_rec_ = driver_rec;
75     }
76 
set_opszx_driver77     void set_ops(const zx_driver_ops_t* ops) {
78         ops_ = ops;
79     }
80 
set_statuszx_driver81     void set_status(zx_status_t status) {
82         status_ = status;
83     }
84 
set_libnamezx_driver85     void set_libname(fbl::StringPiece libname) {
86         libname_ = libname;
87     }
88 
89     // Interface to |ops|. These names contain Op in order to not
90     // collide with e.g. RefPtr names.
91 
has_init_opzx_driver92     bool has_init_op() const {
93         return ops_->init != nullptr;
94     }
95 
has_bind_opzx_driver96     bool has_bind_op() const {
97         return ops_->bind != nullptr;
98     }
99 
has_create_opzx_driver100     bool has_create_op() const {
101         return ops_->create != nullptr;
102     }
103 
InitOpzx_driver104     zx_status_t InitOp() {
105         return ops_->init(&ctx_);
106     }
107 
BindOpzx_driver108     zx_status_t BindOp(devmgr::CreationContext* creation_context,
109                        const fbl::RefPtr<zx_device_t>& device) const {
110         devmgr::devhost_set_creation_context(creation_context);
111         auto status = ops_->bind(ctx_, device.get());
112         devmgr::devhost_set_creation_context(nullptr);
113         return status;
114     }
115 
CreateOpzx_driver116     zx_status_t CreateOp(devmgr::CreationContext* creation_context,
117                          const fbl::RefPtr<zx_device_t>& parent, const char* name, const char* args,
118                          zx_handle_t rpc_channel) const {
119         devmgr::devhost_set_creation_context(creation_context);
120         auto status = ops_->create(ctx_, parent.get(), name, args, rpc_channel);
121         devmgr::devhost_set_creation_context(nullptr);
122         return status;
123     }
124 
ReleaseOpzx_driver125     void ReleaseOp() const {
126         // TODO(kulakowski/teisenbe) Consider poisoning the ops_ table on release.
127         ops_->release(ctx_);
128     }
129 
130 private:
131     friend fbl::unique_ptr<zx_driver> fbl::make_unique<zx_driver>();
132     zx_driver() = default;
133 
134     const char* name_ = nullptr;
135     zx_driver_rec_t* driver_rec_ = nullptr;
136     const zx_driver_ops_t* ops_ = nullptr;
137     void* ctx_ = nullptr;
138     fbl::String libname_;
139     zx_status_t status_ = ZX_OK;
140 };
141 
142 namespace devmgr {
143 
144 extern zx_protocol_device_t device_default_ops;
145 
146 zx_status_t devhost_device_add(const fbl::RefPtr<zx_device_t>& dev,
147                                const fbl::RefPtr<zx_device_t>& parent,
148                                const zx_device_prop_t* props, uint32_t prop_count,
149                                const char* proxy_args) REQ_DM_LOCK;
150 // Note that devhost_device_remove() takes a RefPtr rather than a const RefPtr&.
151 // It intends to consume a reference.
152 zx_status_t devhost_device_remove(fbl::RefPtr<zx_device_t> dev) REQ_DM_LOCK;
153 zx_status_t devhost_device_bind(const fbl::RefPtr<zx_device_t>& dev, const char* drv_libname) REQ_DM_LOCK;
154 zx_status_t devhost_device_rebind(const fbl::RefPtr<zx_device_t>& dev) REQ_DM_LOCK;
155 zx_status_t devhost_device_unbind(const fbl::RefPtr<zx_device_t>& dev) REQ_DM_LOCK;
156 zx_status_t devhost_device_create(zx_driver_t* drv, const fbl::RefPtr<zx_device_t>& parent,
157                                   const char* name, void* ctx,
158                                   zx_protocol_device_t* ops,
159                                   fbl::RefPtr<zx_device_t>* out) REQ_DM_LOCK;
160 zx_status_t devhost_device_open_at(const fbl::RefPtr<zx_device_t>& dev,
161                                    fbl::RefPtr<zx_device_t>* out,
162                                    const char* path, uint32_t flags) REQ_DM_LOCK;
163 zx_status_t devhost_device_close(fbl::RefPtr<zx_device_t> dev, uint32_t flags) REQ_DM_LOCK;
164 zx_status_t devhost_device_suspend(const fbl::RefPtr<zx_device_t>& dev, uint32_t flags) REQ_DM_LOCK;
165 void devhost_device_destroy(zx_device_t* dev) REQ_DM_LOCK;
166 
167 zx_status_t devhost_load_firmware(const fbl::RefPtr<zx_device_t>& dev, const char* path,
168                                   zx_handle_t* fw, size_t* size) REQ_DM_LOCK;
169 
170 zx_status_t devhost_get_topo_path(const fbl::RefPtr<zx_device_t>& dev, char* path,
171                                   size_t max, size_t* actual);
172 
173 zx_status_t devhost_get_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, void* buf,
174                                  size_t buflen, size_t* actual) REQ_DM_LOCK;
175 
176 zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
177                                  const void* data, size_t length) REQ_DM_LOCK;
178 
179 zx_status_t devhost_publish_metadata(const fbl::RefPtr<zx_device_t>& dev, const char* path,
180                                      uint32_t type, const void* data, size_t length) REQ_DM_LOCK;
181 
182 // shared between devhost.c and rpc-device.c
183 struct DevcoordinatorConnection : AsyncLoopOwnedRpcHandler<DevcoordinatorConnection> {
184     DevcoordinatorConnection() = default;
185 
186     static void HandleRpc(fbl::unique_ptr<DevcoordinatorConnection> conn,
187                           async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
188                           const zx_packet_signal_t* signal);
189 
190     fbl::RefPtr<zx_device_t> dev;
191 };
192 
193 struct DevfsConnection : AsyncLoopOwnedRpcHandler<DevfsConnection> {
194     DevfsConnection() = default;
195 
196     static void HandleRpc(fbl::unique_ptr<DevfsConnection> conn,
197                           async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
198                           const zx_packet_signal_t* signal);
199 
200     fbl::RefPtr<zx_device_t> dev;
201     size_t io_off = 0;
202     uint32_t flags = 0;
203 };
204 
205 zx_status_t devhost_fidl_handler(fidl_msg_t* msg, fidl_txn_t* txn, void* cookie);
206 
207 // Attaches channel |c| to new state representing an open connection to |dev|.
208 // |path_data| and |flags| are forwarded to the |dev|'s |open_at| hook.
209 zx_status_t devhost_device_connect(const fbl::RefPtr<zx_device_t>& dev, uint32_t flags,
210                                    const char* path_data, size_t path_size, zx::channel c);
211 
212 zx_status_t devhost_start_connection(fbl::unique_ptr<DevfsConnection> ios, zx::channel h);
213 
214 // routines devhost uses to talk to dev coordinator
215 zx_status_t devhost_add(const fbl::RefPtr<zx_device_t>& dev,
216                         const fbl::RefPtr<zx_device_t>& child, const char* proxy_args,
217                         const zx_device_prop_t* props, uint32_t prop_count) REQ_DM_LOCK;
218 zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) REQ_DM_LOCK;
219 void devhost_make_visible(const fbl::RefPtr<zx_device_t>& dev);
220 
221 // State that is shared between the zx_device implementation and devhost-core.cpp
222 void devhost_finalize() REQ_DM_LOCK;
223 extern fbl::DoublyLinkedList<zx_device*, zx_device::DeferNode> defer_device_list USE_DM_LOCK;
224 extern int devhost_enumerators USE_DM_LOCK;
225 
226 } // namespace devmgr
227