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#include <zircon/compiler.h> 6 7#include <ddk/debug.h> 8#include <ddk/device.h> 9#include "devhost.h" 10 11#include <stdarg.h> 12#include <stdio.h> 13 14// These are the API entry-points from drivers 15// They must take the devhost_api_lock before calling devhost_* internals 16// 17// Driver code MUST NOT directly call devhost_* APIs 18 19 20// LibDriver Device Interface 21 22#define ALLOWED_FLAGS (\ 23 DEVICE_ADD_NON_BINDABLE | DEVICE_ADD_INSTANCE |\ 24 DEVICE_ADD_MUST_ISOLATE | DEVICE_ADD_INVISIBLE) 25 26__EXPORT zx_status_t device_add_from_driver(zx_driver_t* drv, zx_device_t* parent, 27 device_add_args_t* args, zx_device_t** out) { 28 zx_status_t r; 29 zx_device_t* dev = nullptr; 30 31 if (!parent) { 32 return ZX_ERR_INVALID_ARGS; 33 } 34 if (!args || args->version != DEVICE_ADD_ARGS_VERSION) { 35 return ZX_ERR_INVALID_ARGS; 36 } 37 if (!args->ops || args->ops->version != DEVICE_OPS_VERSION) { 38 return ZX_ERR_INVALID_ARGS; 39 } 40 if (args->flags & ~ALLOWED_FLAGS) { 41 return ZX_ERR_INVALID_ARGS; 42 } 43 if ((args->flags & DEVICE_ADD_INSTANCE) && 44 (args->flags & (DEVICE_ADD_MUST_ISOLATE | DEVICE_ADD_INVISIBLE))) { 45 return ZX_ERR_INVALID_ARGS; 46 } 47 48 DM_LOCK(); 49 r = devhost_device_create(drv, parent, args->name, args->ctx, args->ops, &dev); 50 if (r != ZX_OK) { 51 DM_UNLOCK(); 52 return r; 53 } 54 if (args->proto_id) { 55 dev->protocol_id = args->proto_id; 56 dev->protocol_ops = args->proto_ops; 57 } 58 if (args->flags & DEVICE_ADD_NON_BINDABLE) { 59 dev->flags |= DEV_FLAG_UNBINDABLE; 60 } 61 if (args->flags & DEVICE_ADD_INVISIBLE) { 62 dev->flags |= DEV_FLAG_INVISIBLE; 63 } 64 65 // out must be set before calling devhost_device_add(). 66 // devhost_device_add() may result in child devices being created before it returns, 67 // and those children may call ops on the device before device_add() returns. 68 if (out) { 69 *out = dev; 70 } 71 72 if (args->flags & DEVICE_ADD_MUST_ISOLATE) { 73 r = devhost_device_add(dev, parent, args->props, args->prop_count, args->proxy_args); 74 } else if (args->flags & DEVICE_ADD_INSTANCE) { 75 dev->flags |= DEV_FLAG_INSTANCE | DEV_FLAG_UNBINDABLE; 76 r = devhost_device_add(dev, parent, nullptr, 0, nullptr); 77 } else { 78 r = devhost_device_add(dev, parent, args->props, args->prop_count, nullptr); 79 } 80 if (r != ZX_OK) { 81 if (out) { 82 *out = nullptr; 83 } 84 devhost_device_destroy(dev); 85 } 86 87 DM_UNLOCK(); 88 return r; 89} 90 91__EXPORT zx_status_t device_remove(zx_device_t* dev) { 92 zx_status_t r; 93 DM_LOCK(); 94 r = devhost_device_remove(dev); 95 DM_UNLOCK(); 96 return r; 97} 98 99__EXPORT zx_status_t device_rebind(zx_device_t* dev) { 100 zx_status_t r; 101 DM_LOCK(); 102 r = devhost_device_rebind(dev); 103 DM_UNLOCK(); 104 return r; 105} 106 107__EXPORT void device_make_visible(zx_device_t* dev) { 108 DM_LOCK(); 109 devhost_make_visible(dev); 110 DM_UNLOCK(); 111} 112 113 114__EXPORT const char* device_get_name(zx_device_t* dev) { 115 return dev->name; 116} 117 118__EXPORT zx_device_t* device_get_parent(zx_device_t* dev) { 119 return dev->parent; 120} 121 122typedef struct { 123 void* ops; 124 void* ctx; 125} generic_protocol_t; 126 127__EXPORT zx_status_t device_get_protocol(const zx_device_t* dev, uint32_t proto_id, void* out) { 128 auto proto = static_cast<generic_protocol_t*>(out); 129 if (dev->ops->get_protocol) { 130 return dev->ops->get_protocol(dev->ctx, proto_id, out); 131 } 132 if ((proto_id == dev->protocol_id) && (dev->protocol_ops != nullptr)) { 133 proto->ops = dev->protocol_ops; 134 proto->ctx = dev->ctx; 135 return ZX_OK; 136 } 137 return ZX_ERR_NOT_SUPPORTED; 138} 139 140__EXPORT void device_state_clr_set(zx_device_t* dev, zx_signals_t clearflag, zx_signals_t setflag) { 141 zx_object_signal(dev->event, clearflag, setflag); 142} 143 144 145__EXPORT zx_off_t device_get_size(zx_device_t* dev) { 146 return dev->ops->get_size(dev->ctx); 147} 148 149__EXPORT zx_status_t device_read(zx_device_t* dev, void* buf, size_t count, 150 zx_off_t off, size_t* actual) { 151 return dev->ops->read(dev->ctx, buf, count, off, actual); 152} 153 154__EXPORT zx_status_t device_write(zx_device_t* dev, const void* buf, size_t count, 155 zx_off_t off, size_t* actual) { 156 return dev->ops->write(dev->ctx, buf, count, off, actual); 157} 158 159__EXPORT zx_status_t device_ioctl(zx_device_t* dev, uint32_t op, 160 const void* in_buf, size_t in_len, 161 void* out_buf, size_t out_len, 162 size_t* out_actual) { 163 return dev->ops->ioctl(dev->ctx, op, in_buf, in_len, out_buf, out_len, out_actual); 164} 165 166// LibDriver Misc Interfaces 167 168extern zx_handle_t root_resource_handle; 169 170__EXPORT zx_handle_t get_root_resource() { 171 return root_resource_handle; 172} 173 174__EXPORT zx_status_t load_firmware(zx_device_t* dev, const char* path, 175 zx_handle_t* fw, size_t* size) { 176 zx_status_t r; 177 DM_LOCK(); 178 r = devhost_load_firmware(dev, path, fw, size); 179 DM_UNLOCK(); 180 return r; 181} 182 183// Interface Used by DevHost RPC Layer 184 185zx_status_t device_bind(zx_device_t* dev, const char* drv_libname) { 186 zx_status_t r; 187 DM_LOCK(); 188 r = devhost_device_bind(dev, drv_libname); 189 DM_UNLOCK(); 190 return r; 191} 192 193zx_status_t device_open_at(zx_device_t* dev, zx_device_t** out, const char* path, uint32_t flags) { 194 zx_status_t r; 195 DM_LOCK(); 196 r = devhost_device_open_at(dev, out, path, flags); 197 DM_UNLOCK(); 198 return r; 199} 200 201zx_status_t device_close(zx_device_t* dev, uint32_t flags) { 202 zx_status_t r; 203 DM_LOCK(); 204 r = devhost_device_close(dev, flags); 205 DM_UNLOCK(); 206 return r; 207} 208 209__EXPORT zx_status_t device_get_metadata(zx_device_t* dev, uint32_t type, void* buf, size_t buflen, 210 size_t* actual) { 211 zx_status_t r; 212 DM_LOCK(); 213 r = devhost_get_metadata(dev, type, buf, buflen, actual); 214 DM_UNLOCK(); 215 return r; 216} 217 218__EXPORT zx_status_t device_add_metadata(zx_device_t* dev, uint32_t type, const void* data, 219 size_t length) { 220 zx_status_t r; 221 DM_LOCK(); 222 r = devhost_add_metadata(dev, type, data, length); 223 DM_UNLOCK(); 224 return r; 225} 226 227__EXPORT zx_status_t device_publish_metadata(zx_device_t* dev, const char* path, uint32_t type, 228 const void* data, size_t length) { 229 zx_status_t r; 230 DM_LOCK(); 231 r = devhost_publish_metadata(dev, path, type, data, length); 232 DM_UNLOCK(); 233 return r; 234} 235