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 <atomic>
8 #include <ddk/device.h>
9 #include <fbl/intrusive_double_list.h>
10 #include <fbl/mutex.h>
11 #include <fbl/recycler.h>
12 #include <fbl/ref_counted.h>
13 #include <fbl/ref_ptr.h>
14 #include <lib/zx/channel.h>
15 #include <lib/zx/eventpair.h>
16 #include <zircon/compiler.h>
17 #include <zircon/thread_annotations.h>
18 
19 namespace devmgr {
20 
21 struct DevcoordinatorConnection;
22 struct ProxyIostate;
23 
24 } // namespace devmgr
25 
26 #define DEV_MAGIC 'MDEV'
27 
28 // This needs to be a struct, not a class, to match the public definition
29 struct zx_device : fbl::RefCounted<zx_device>, fbl::Recyclable<zx_device>  {
30     ~zx_device() = default;
31 
32     zx_device(const zx_device&) = delete;
33     zx_device& operator=(const zx_device&) = delete;
34 
35     static zx_status_t Create(fbl::RefPtr<zx_device>* out_dev);
36 
OpenOpzx_device37     zx_status_t OpenOp(zx_device_t** dev_out, uint32_t flags) {
38         return ops->open(ctx, dev_out, flags);
39     }
40 
OpenAtOpzx_device41     zx_status_t OpenAtOp(zx_device_t** dev_out, const char* path, uint32_t flags) {
42         return ops->open_at(ctx, dev_out, path, flags);
43     }
44 
CloseOpzx_device45     zx_status_t CloseOp(uint32_t flags) {
46         return ops->close(ctx, flags);
47     }
48 
UnbindOpzx_device49     void UnbindOp() {
50         ops->unbind(ctx);
51     }
52 
ReleaseOpzx_device53     void ReleaseOp() {
54         ops->release(ctx);
55     }
56 
SuspendOpzx_device57     zx_status_t SuspendOp(uint32_t flags) {
58         return ops->suspend(ctx, flags);
59     }
60 
ResumeOpzx_device61     zx_status_t ResumeOp(uint32_t flags) {
62         return ops->resume(ctx, flags);
63     }
64 
ReadOpzx_device65     zx_status_t ReadOp(void* buf, size_t count, zx_off_t off,
66                        size_t* actual) {
67         return ops->read(ctx, buf, count, off, actual);
68     }
69 
WriteOpzx_device70     zx_status_t WriteOp(const void* buf, size_t count,
71                         zx_off_t off, size_t* actual) {
72         return ops->write(ctx, buf, count, off, actual);
73     }
74 
GetSizeOpzx_device75     zx_off_t GetSizeOp() {
76         return ops->get_size(ctx);
77     }
78 
IoctlOpzx_device79     zx_status_t IoctlOp(uint32_t op, const void* in_buf, size_t in_len,
80                         void* out_buf, size_t out_len, size_t* out_actual) {
81         return ops->ioctl(ctx, op, in_buf, in_len, out_buf, out_len, out_actual);
82     }
83 
MessageOpzx_device84     zx_status_t MessageOp(fidl_msg_t* msg, fidl_txn_t* txn) {
85         return ops->message(ctx, msg, txn);
86     }
87 
88     uintptr_t magic = DEV_MAGIC;
89 
90     zx_protocol_device_t* ops = nullptr;
91 
92     // reserved for driver use; will not be touched by devmgr
93     void* ctx = nullptr;
94 
95     uint32_t flags = 0;
96 
97     zx::eventpair event;
98     zx::eventpair local_event;
99     // The RPC channel is owned by |conn|
100     zx::unowned_channel rpc;
101 
102     // most devices implement a single
103     // protocol beyond the base device protocol
104     uint32_t protocol_id = 0;
105     void* protocol_ops = nullptr;
106 
107     // driver that has published this device
108     zx_driver_t* driver = nullptr;
109 
110     // parent in the device tree
111     fbl::RefPtr<zx_device_t> parent;
112 
113     // for the parent's device_list
114     fbl::DoublyLinkedListNodeState<zx_device*> node;
115     struct Node {
node_statezx_device::Node116         static fbl::DoublyLinkedListNodeState<zx_device*>& node_state(
117             zx_device& obj) {
118             return obj.node;
119         }
120     };
121 
122     // list of this device's children in the device tree
123     fbl::DoublyLinkedList<zx_device*, Node> children;
124 
125     // list node for the defer_device_list
126     fbl::DoublyLinkedListNodeState<zx_device*> defer;
127     struct DeferNode {
node_statezx_device::DeferNode128         static fbl::DoublyLinkedListNodeState<zx_device*>& node_state(
129             zx_device& obj) {
130             return obj.defer;
131         }
132     };
133 
134     // This is an atomic so that the connection's async loop can inspect this
135     // value to determine if an expected shutdown is happening.  See comments in
136     // devhost_remove().
137     std::atomic<devmgr::DevcoordinatorConnection*> conn = nullptr;
138 
139     fbl::Mutex proxy_ios_lock;
140     devmgr::ProxyIostate* proxy_ios TA_GUARDED(proxy_ios_lock) = nullptr;
141 
142     char name[ZX_DEVICE_NAME_MAX + 1] = {};
143 private:
144     zx_device() = default;
145 
146     friend class fbl::Recyclable<zx_device_t>;
147     void fbl_recycle();
148 };
149 
150 // zx_device_t objects must be created or initialized by the driver manager's
151 // device_create() function.  Drivers MAY NOT touch any
152 // fields in the zx_device_t, except for the protocol_id and protocol_ops
153 // fields which it may fill out after init and before device_add() is called,
154 // and the ctx field which may be used to store driver-specific data.
155 
156 #define DEV_FLAG_DEAD           0x00000001  // being deleted
157 #define DEV_FLAG_VERY_DEAD      0x00000002  // safe for ref0 and release()
158 #define DEV_FLAG_UNBINDABLE     0x00000004  // nobody may bind to this device
159 #define DEV_FLAG_BUSY           0x00000010  // device being created
160 #define DEV_FLAG_INSTANCE       0x00000020  // this device was created-on-open
161 #define DEV_FLAG_MULTI_BIND     0x00000080  // this device accepts many children
162 #define DEV_FLAG_ADDED          0x00000100  // device_add() has been called for this device
163 #define DEV_FLAG_INVISIBLE      0x00000200  // device not visible via devfs
164 #define DEV_FLAG_UNBOUND        0x00000400  // informed that it should self-delete asap
165 #define DEV_FLAG_WANTS_REBIND   0x00000800  // when last child goes, rebind this device
166 
167 zx_status_t device_bind(const fbl::RefPtr<zx_device_t>& dev, const char* drv_libname);
168 zx_status_t device_unbind(const fbl::RefPtr<zx_device_t>& dev);
169 zx_status_t device_open_at(const fbl::RefPtr<zx_device_t>& dev, fbl::RefPtr<zx_device_t>* out,
170                            const char* path, uint32_t flags);
171 // Note that device_close() is intended to consume a reference (logically, the
172 // one created by device_open_at).
173 zx_status_t device_close(fbl::RefPtr<zx_device_t> dev, uint32_t flags);
174