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