diff --git a/zircon/system/core/devmgr/devcoordinator/composite-device.cpp b/zircon/system/core/devmgr/devcoordinator/composite-device.cpp index 02e09885eb047da12a81d86d264d4894274d4044..87836333d934930ed90ab2fc4aa7f900910f16b6 100644 --- a/zircon/system/core/devmgr/devcoordinator/composite-device.cpp +++ b/zircon/system/core/devmgr/devcoordinator/composite-device.cpp @@ -5,6 +5,7 @@ #include "composite-device.h" #include <utility> +#include <zircon/status.h> #include "../shared/log.h" #include "binding-internal.h" #include "coordinator.h" @@ -14,13 +15,9 @@ namespace devmgr { // CompositeDevice methods CompositeDevice::CompositeDevice(fbl::String name, fbl::Array<const zx_device_prop_t> properties, - uint32_t coresident_device_index) + uint32_t components_count, uint32_t coresident_device_index) : name_(std::move(name)), properties_(std::move(properties)), - coresident_device_index_(coresident_device_index) { - // TODO(teisenbe): Remove this when the index is used elsewhere. Clang and - // GCC do not agree on whether this is unused, so either tagging it as used - // or unused causes one of them to error. - (void)coresident_device_index_; + components_count_(components_count), coresident_device_index_(coresident_device_index) { } CompositeDevice::~CompositeDevice() = default; @@ -30,13 +27,17 @@ zx_status_t CompositeDevice::Create(const fbl::StringPiece& name, const fuchsia_device_manager_DeviceComponent* components, size_t components_count, uint32_t coresident_device_index, std::unique_ptr<CompositeDevice>* out) { + if (components_count > UINT32_MAX) { + return ZX_ERR_INVALID_ARGS; + } + fbl::String name_obj(name); fbl::Array<zx_device_prop_t> properties(new zx_device_prop_t[props_count], props_count); memcpy(properties.get(), props_data, props_count * sizeof(props_data[0])); auto dev = std::make_unique<CompositeDevice>(std::move(name), std::move(properties), - coresident_device_index); - for (size_t i = 0; i < components_count; ++i) { + components_count, coresident_device_index); + for (uint32_t i = 0; i < components_count; ++i) { const auto& fidl_component = components[i]; size_t parts_count = fidl_component.parts_count; fbl::Array<ComponentPartDescriptor> parts(new ComponentPartDescriptor[parts_count], @@ -118,6 +119,9 @@ zx_status_t CompositeDevice::TryAssemble() { } } + Coordinator* coordinator = nullptr; + uint64_t component_local_ids[fuchsia_device_manager_COMPONENTS_MAX] = {}; + // Create all of the proxies for the component devices, in the same process for (auto& component : bound_) { const fbl::RefPtr<Device>& dev = component.component_device(); @@ -128,7 +132,8 @@ zx_status_t CompositeDevice::TryAssemble() { log(ERROR, "devcoordinator: cannot create composite, proxies in different processes\n"); return ZX_ERR_BAD_STATE; } - zx_status_t status = dev->coordinator->PrepareProxy(dev, devhost); + coordinator = dev->coordinator; + zx_status_t status = coordinator->PrepareProxy(dev, devhost); if (status != ZX_OK) { return status; } @@ -137,9 +142,39 @@ zx_status_t CompositeDevice::TryAssemble() { devhost = dev->proxy->host(); ZX_ASSERT(devhost != nullptr); } + // Stash the local ID after the proxy has been created + component_local_ids[component.index()] = dev->proxy->local_id(); + } + + zx::channel rpc_local, rpc_remote; + zx_status_t status = zx::channel::create(0, &rpc_local, &rpc_remote); + if (status != ZX_OK) { + return status; + } + + fbl::RefPtr<Device> new_device; + status = Device::CreateComposite(coordinator, devhost, *this, std::move(rpc_local), + &new_device); + if (status != ZX_OK) { + return status; } - // TODO: Create the composite device and wire everything up - return ZX_ERR_NOT_SUPPORTED; + coordinator->devices().push_back(new_device); + + // Create the composite device in the devhost + status = dh_send_create_composite_device(devhost, new_device.get(), *this, component_local_ids, + std::move(rpc_remote)); + if (status != ZX_OK) { + log(ERROR, "devcoordinator: create composite device request failed: %s\n", + zx_status_get_string(status)); + return status; + } + + status = new_device->SignalReadyForBind(); + if (status != ZX_OK) { + return status; + } + + return ZX_OK; } // CompositeDeviceComponent methods diff --git a/zircon/system/core/devmgr/devcoordinator/composite-device.h b/zircon/system/core/devmgr/devcoordinator/composite-device.h index b4b575d5e323623663690e54c226157d1a0cd429..2f4e142666bbe3312f3538714caea520c3077771 100644 --- a/zircon/system/core/devmgr/devcoordinator/composite-device.h +++ b/zircon/system/core/devmgr/devcoordinator/composite-device.h @@ -92,7 +92,7 @@ class CompositeDevice { public: // Only public because of make_unique. You probably want Create(). CompositeDevice(fbl::String name, fbl::Array<const zx_device_prop_t> properties, - uint32_t coresident_device_index); + uint32_t components_count, uint32_t coresident_device_index); CompositeDevice(CompositeDevice&&) = delete; CompositeDevice& operator=(CompositeDevice&&) = delete; @@ -114,6 +114,7 @@ public: const fbl::Array<const zx_device_prop_t>& properties() const { return properties_; } + uint32_t components_count() const { return components_count_; } // Attempt to match any of the unbound components against |dev|. Returns true // if a component was match. |*component_out| will be set to the index of @@ -141,6 +142,7 @@ private: const fbl::String name_; const fbl::Array<const zx_device_prop_t> properties_; + const uint32_t components_count_; const uint32_t coresident_device_index_; ComponentList unbound_; diff --git a/zircon/system/core/devmgr/devcoordinator/coordinator.cpp b/zircon/system/core/devmgr/devcoordinator/coordinator.cpp index 9c2fbaa712cd5c5e90989783dde3eec65eae6ced..1ffb4960e679d931a8e196c2127f37c856ba70f4 100644 --- a/zircon/system/core/devmgr/devcoordinator/coordinator.cpp +++ b/zircon/system/core/devmgr/devcoordinator/coordinator.cpp @@ -929,10 +929,7 @@ zx_status_t Coordinator::AddCompositeDevice( return ZX_OK; // TODO: - // - Logic for creating the new bindpoint once the bookkeeping finds - // everything is ready // - Logic for sending an unbind() when some component goes away - // - Implementation of Composite Banjo protocol // // Tests to write: // - Introducing a composite device when all components are already ready diff --git a/zircon/system/core/devmgr/devcoordinator/coordinator.h b/zircon/system/core/devmgr/devcoordinator/coordinator.h index 299776c118f5e1be7e34adca4545fac53b8d2e70..c98632666a5152ea9749e39e38ac85f7732fc3fc 100644 --- a/zircon/system/core/devmgr/devcoordinator/coordinator.h +++ b/zircon/system/core/devmgr/devcoordinator/coordinator.h @@ -338,5 +338,8 @@ zx_status_t dh_send_create_device_stub(Device* dev, Devhost* dh, zx::channel rpc zx_status_t dh_send_bind_driver(const Device* dev, const char* libname, zx::vmo driver); zx_status_t dh_send_connect_proxy(const Device* dev, zx::channel proxy); zx_status_t dh_send_suspend(const Device* dev, uint32_t flags); +zx_status_t dh_send_create_composite_device(Devhost* dh, const Device* composite_dev, + const CompositeDevice& composite, + const uint64_t* component_local_ids, zx::channel rpc); } // namespace devmgr diff --git a/zircon/system/core/devmgr/devcoordinator/device.cpp b/zircon/system/core/devmgr/devcoordinator/device.cpp index 337ede8910126dd382ccfb2c01c61819f8e6fd9c..a83e2240986fdc9cce1292d67b5a856d8f57c5bc 100644 --- a/zircon/system/core/devmgr/devcoordinator/device.cpp +++ b/zircon/system/core/devmgr/devcoordinator/device.cpp @@ -4,6 +4,7 @@ #include "device.h" +#include <ddk/driver.h> #include "../shared/log.h" #include "coordinator.h" #include "devfs.h" @@ -107,6 +108,51 @@ zx_status_t Device::Create(Coordinator* coordinator, const fbl::RefPtr<Device>& return ZX_OK; } +zx_status_t Device::CreateComposite(Coordinator* coordinator, Devhost* devhost, + const CompositeDevice& composite, zx::channel rpc, + fbl::RefPtr<Device>* device) { + const auto& composite_props = composite.properties(); + fbl::Array<zx_device_prop_t> props(new zx_device_prop_t[composite_props.size()], + composite_props.size()); + memcpy(props.get(), composite_props.get(), props.size() * sizeof(props[0])); + + auto dev = fbl::MakeRefCounted<Device>(coordinator); + if (!dev) { + return ZX_ERR_NO_MEMORY; + } + + zx_status_t status = dev->SetProps(std::move(props)); + if (status != ZX_OK) { + return status; + } + + dev->name = composite.name(); + dev->set_channel(std::move(rpc)); + dev->set_protocol_id(ZX_PROTOCOL_COMPOSITE); + // We exist within our parent's device host + dev->set_host(devhost); + + // TODO: Record composite membership + + // TODO(teisenbe): Figure out how to manifest in devfs? For now just hang it off of + // the root device? + if ((status = devfs_publish(coordinator->root_device(), dev)) < 0) { + return status; + } + + if ((status = Device::BeginWait(dev, coordinator->dispatcher())) != ZX_OK) { + return status; + } + + dev->host_->AddRef(); + dev->host_->devices().push_back(dev.get()); + + log(DEVLC, "devcoordinator: composite dev created %p name='%s'\n", dev.get(), dev->name.data()); + + *device = std::move(dev); + return ZX_OK; +} + zx_status_t Device::CreateProxy() { ZX_ASSERT(this->proxy == nullptr); diff --git a/zircon/system/core/devmgr/devcoordinator/device.h b/zircon/system/core/devmgr/devcoordinator/device.h index 9da6b3e478f12838919e55803c9598c439fcd4b7..f1c45cabffb67291b4bc7a0d19f9047366fc0e95 100644 --- a/zircon/system/core/devmgr/devcoordinator/device.h +++ b/zircon/system/core/devmgr/devcoordinator/device.h @@ -17,6 +17,7 @@ namespace devmgr { +class CompositeDevice; class CompositeDeviceComponent; class Coordinator; class Devhost; @@ -66,6 +67,9 @@ struct Device : public fbl::RefCounted<Device>, public AsyncLoopRefCountedRpcHan uint32_t protocol_id, fbl::Array<zx_device_prop_t> props, zx::channel rpc, bool invisible, zx::channel client_remote, fbl::RefPtr<Device>* device); + static zx_status_t CreateComposite(Coordinator* coordinator, Devhost* devhost, + const CompositeDevice& composite, zx::channel rpc, + fbl::RefPtr<Device>* device); zx_status_t CreateProxy(); static void HandleRpc(fbl::RefPtr<Device>&& dev, async_dispatcher_t* dispatcher, diff --git a/zircon/system/core/devmgr/devcoordinator/fidl.cpp b/zircon/system/core/devmgr/devcoordinator/fidl.cpp index bb08a7d07b32216bece37a5d0674fb37e75460dd..ee8b26dc4e3eab5337d7a696f62f36b6020e0bd6 100644 --- a/zircon/system/core/devmgr/devcoordinator/fidl.cpp +++ b/zircon/system/core/devmgr/devcoordinator/fidl.cpp @@ -150,4 +150,43 @@ zx_status_t dh_send_suspend(const Device* dev, uint32_t flags) { return msg.Write(dev->channel()->get(), 0); } +zx_status_t dh_send_create_composite_device(Devhost* dh, const Device* composite_dev, + const CompositeDevice& composite, + const uint64_t* component_local_ids, zx::channel rpc) { + size_t components_size = composite.components_count() * sizeof(uint64_t); + size_t name_size = composite.name().size(); + uint32_t wr_num_bytes = static_cast<uint32_t>( + sizeof(fuchsia_device_manager_ControllerCreateCompositeDeviceRequest) + + FIDL_ALIGN(components_size) + FIDL_ALIGN(name_size)); + FIDL_ALIGNDECL char wr_bytes[wr_num_bytes]; + fidl::Builder builder(wr_bytes, wr_num_bytes); + + auto req = builder.New<fuchsia_device_manager_ControllerCreateCompositeDeviceRequest>(); + uint64_t* components_data = builder.NewArray<uint64_t>( + static_cast<uint32_t>(composite.components_count())); + char* name_data = builder.NewArray<char>(static_cast<uint32_t>(name_size)); + ZX_ASSERT(req != nullptr && components_data != nullptr && name_data != nullptr); + req->hdr.ordinal = fuchsia_device_manager_ControllerCreateCompositeDeviceOrdinal; + // TODO(teisenbe): Allocate and track txids + req->hdr.txid = 1; + + req->rpc = FIDL_HANDLE_PRESENT; + + req->components.count = composite.components_count(); + req->components.data = reinterpret_cast<char*>(FIDL_ALLOC_PRESENT); + memcpy(components_data, component_local_ids, components_size); + + req->name.size = name_size; + req->name.data = reinterpret_cast<char*>(FIDL_ALLOC_PRESENT); + memcpy(name_data, composite.name().data(), name_size); + + req->local_device_id = composite_dev->local_id(); + + zx_handle_t handles[1] = {rpc.release()}; + uint32_t num_handles = 1; + + fidl::Message msg(builder.Finalize(), fidl::HandlePart(handles, num_handles, num_handles)); + return msg.Write(dh->hrpc(), 0); +} + } // namespace devmgr diff --git a/zircon/system/core/devmgr/devhost/BUILD.gn b/zircon/system/core/devmgr/devhost/BUILD.gn index 356d28374cd59c389563997922f2848ac33b6342..a328c7e803f624439187e572e6aaadd5dfaac459 100644 --- a/zircon/system/core/devmgr/devhost/BUILD.gn +++ b/zircon/system/core/devmgr/devhost/BUILD.gn @@ -19,6 +19,7 @@ library("driver") { static = false sources = [ "api.cpp", + "composite-device.cpp", "core.cpp", "devhost.cpp", "rpc-server.cpp", @@ -27,6 +28,7 @@ library("driver") { ] configs += [ "$zx/public/gn/config:visibility_hidden" ] deps = [ + "$zx/system/banjo/ddk-protocol-composite", "$zx/system/fidl/fuchsia-device:c", "$zx/system/fidl/fuchsia-device-manager:c", "$zx/system/fidl/fuchsia-io:c", @@ -42,8 +44,8 @@ library("driver") { "$zx/system/ulib/sync", "$zx/system/ulib/trace:trace-driver", "$zx/system/ulib/trace-provider:static", - "$zx/system/ulib/zircon-internal", "$zx/system/ulib/zircon", + "$zx/system/ulib/zircon-internal", "$zx/system/ulib/zx", "$zx/system/ulib/zxcpp", "$zx/system/ulib/zxio", diff --git a/zircon/system/core/devmgr/devhost/composite-device.cpp b/zircon/system/core/devmgr/devhost/composite-device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62d228a05247b071aa1a0b656d95778aeb99e4e8 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/composite-device.cpp @@ -0,0 +1,88 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "composite-device.h" + +#include <algorithm> +#include <ddk/protocol/composite.h> +#include "device-internal.h" + +namespace devmgr { + +namespace { + +class CompositeDevice { +public: + CompositeDevice(zx_device_t* zxdev, CompositeComponents&& components) + : zxdev_(zxdev), components_(std::move(components)) { } + + static zx_status_t Create(zx_device_t* zxdev, CompositeComponents&& components, + std::unique_ptr<CompositeDevice>* device) { + auto dev = std::make_unique<CompositeDevice>(zxdev, std::move(components)); + *device = std::move(dev); + return ZX_OK; + } + + uint32_t GetComponentCount() { + return static_cast<uint32_t>(components_.size()); + } + + void GetComponents(zx_device_t** comp_list, size_t comp_count, size_t* comp_actual) { + size_t actual = std::min(comp_count, components_.size()); + for (size_t i = 0; i < actual; ++i) { + comp_list[i] = components_[i].get(); + } + *comp_actual = actual; + } + + void Release() { + delete this; + } + + void Unbind() { + device_remove(zxdev_); + } +private: + zx_device_t* zxdev_; + const CompositeComponents components_; +}; + +} // namespace + +zx_status_t InitializeCompositeDevice(const fbl::RefPtr<zx_device>& dev, + CompositeComponents&& components) { + static const zx_protocol_device_t composite_device_ops = []() { + zx_protocol_device_t ops = {}; + ops.unbind = [](void* ctx) { static_cast<CompositeDevice*>(ctx)->Unbind(); }; + ops.release = [](void* ctx) { static_cast<CompositeDevice*>(ctx)->Release(); }; + return ops; + }(); + static composite_protocol_ops_t composite_ops = []() { + composite_protocol_ops_t ops = {}; + ops.get_component_count = [](void* ctx) { + return static_cast<CompositeDevice*>(ctx)->GetComponentCount(); + }; + ops.get_components = [](void* ctx, zx_device_t** comp_list, size_t comp_count, + size_t* comp_actual) { + static_cast<CompositeDevice*>(ctx)->GetComponents(comp_list, comp_count, comp_actual); + }; + return ops; + }(); + + std::unique_ptr<CompositeDevice> new_device; + zx_status_t status = CompositeDevice::Create(dev.get(), std::move(components), &new_device); + if (status != ZX_OK) { + return status; + } + + dev->protocol_id = ZX_PROTOCOL_COMPOSITE; + dev->protocol_ops = &composite_ops; + dev->ops = &composite_device_ops; + dev->ctx = new_device.release(); + // Flag that when this is cleaned up, we should run its release hook. + dev->flags |= DEV_FLAG_ADDED; + return ZX_OK; +} + +} // namespace devmgr diff --git a/zircon/system/core/devmgr/devhost/composite-device.h b/zircon/system/core/devmgr/devhost/composite-device.h new file mode 100644 index 0000000000000000000000000000000000000000..aefec95c7748f5ef6cd00c87178f63a774787128 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/composite-device.h @@ -0,0 +1,21 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include <ddk/driver.h> +#include <fbl/array.h> +#include <fbl/ref_ptr.h> +#include "device-internal.h" + +namespace devmgr { + +typedef fbl::Array<fbl::RefPtr<zx_device>> CompositeComponents; + +// Modifies |device| to have the appropriate protocol_id, ctx, and ops tables +// for a composite device +zx_status_t InitializeCompositeDevice(const fbl::RefPtr<zx_device>& device, + CompositeComponents&& components); + +} // namespace devmgr diff --git a/zircon/system/core/devmgr/devhost/devhost.cpp b/zircon/system/core/devmgr/devhost/devhost.cpp index 3a3adf2bc74631e1bdbd58940f1776379ed04a7e..9fc0440f7e8e0323fcc4859b36e216b43a7589fe 100644 --- a/zircon/system/core/devmgr/devhost/devhost.cpp +++ b/zircon/system/core/devmgr/devhost/devhost.cpp @@ -44,6 +44,7 @@ #include "../shared/env.h" #include "../shared/fidl_txn.h" #include "../shared/log.h" +#include "composite-device.h" #include "main.h" #include "tracing.h" @@ -477,6 +478,69 @@ static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc, return ZX_OK; } +static zx_status_t fidl_CreateCompositeDevice(void* raw_ctx, zx_handle_t raw_rpc, + const uint64_t* component_local_ids_data, + size_t component_local_ids_count, + const char* name_data, size_t name_size, + uint64_t device_local_id, fidl_txn_t* txn) { + auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx); + zx::channel rpc(raw_rpc); + fbl::StringPiece name(name_data, name_size); + + log(RPC_IN, "devhost[%s] create composite device %.*s'\n", ctx->path, + static_cast<int>(name_size), name_data); + + auto newconn = fbl::make_unique<DevcoordinatorConnection>(); + if (!newconn) { + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply(txn, ZX_ERR_NO_MEMORY); + } + + // Convert the component IDs into zx_device references + CompositeComponents components_list(new fbl::RefPtr<zx_device>[component_local_ids_count], + component_local_ids_count); + { + // Acquire the API lock so that we don't have to worry about concurrent + // device removes + ApiAutoLock lock; + + for (size_t i = 0; i < component_local_ids_count; ++i) { + uint64_t local_id = component_local_ids_data[i]; + fbl::RefPtr<zx_device_t> dev = zx_device::GetDeviceFromLocalId(local_id); + if (dev == nullptr || (dev->flags & DEV_FLAG_DEAD)) { + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply( + txn, ZX_ERR_NOT_FOUND); + } + components_list[i] = std::move(dev); + } + } + + fbl::RefPtr<zx_device_t> dev; + zx_status_t status = zx_device::Create(&dev); + if (status != ZX_OK) { + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply(txn, status); + } + static_assert(fuchsia_device_manager_DEVICE_NAME_MAX + 1 >= sizeof(dev->name)); + memcpy(dev->name, name_data, name_size); + dev->name[name_size] = 0; + dev->rpc = zx::unowned_channel(rpc); + dev->set_local_id(device_local_id); + + status = InitializeCompositeDevice(dev, std::move(components_list)); + if (status != ZX_OK) { + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply(txn, status); + } + + newconn->dev = dev; + + newconn->set_channel(std::move(rpc)); + log(RPC_IN, "devhost[%s] creating new composite conn=%p\n", ctx->path, newconn.get()); + if ((status = DevcoordinatorConnection::BeginWait(std::move(newconn), + DevhostAsyncLoop()->dispatcher())) != ZX_OK) { + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply(txn, status); + } + return fuchsia_device_manager_ControllerCreateCompositeDevice_reply(txn, ZX_OK); +} + static zx_status_t fidl_BindDriver(void* raw_ctx, const char* driver_path_data, size_t driver_path_size, zx_handle_t raw_driver_vmo, fidl_txn_t* txn) { @@ -566,6 +630,7 @@ static fuchsia_device_manager_Controller_ops_t fidl_ops = { .ConnectProxy = fidl_ConnectProxy, .Suspend = fidl_Suspend, .RemoveDevice = fidl_RemoveDevice, + .CreateCompositeDevice = fidl_CreateCompositeDevice, }; static zx_status_t dh_handle_rpc_read(zx_handle_t h, DevcoordinatorConnection* conn) { @@ -997,6 +1062,9 @@ zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) { zx_status_t status = fuchsia_device_manager_CoordinatorRemoveDevice(rpc.get(), &call_status); log_rpc_result("remove-device", status, call_status); + // Forget our local ID, to release the reference stored by the local ID map + dev->set_local_id(0); + // Forget about our rpc channel since after the port_queue below it may be // closed. dev->rpc = zx::unowned_channel(); diff --git a/zircon/system/core/devmgr/devhost/device-internal.h b/zircon/system/core/devmgr/devhost/device-internal.h index 50f96ad3952b1120643514c6b705c7bc706f1fbd..ce98d3e5f3c5b3645912297371b6731a3bb2b67b 100644 --- a/zircon/system/core/devmgr/devhost/device-internal.h +++ b/zircon/system/core/devmgr/devhost/device-internal.h @@ -7,6 +7,7 @@ #include <atomic> #include <ddk/device.h> #include <fbl/intrusive_double_list.h> +#include <fbl/intrusive_wavl_tree.h> #include <fbl/mutex.h> #include <fbl/recycler.h> #include <fbl/ref_counted_upgradeable.h> @@ -83,8 +84,12 @@ struct zx_device : fbl::RefCountedUpgradeable<zx_device>, fbl::Recyclable<zx_dev return Dispatch(ops->message, ZX_ERR_NOT_SUPPORTED, msg, txn); } + // Check if this devhost has a device with the given ID, and if so returns a + // reference to it. + static fbl::RefPtr<zx_device> GetDeviceFromLocalId(uint64_t local_id); + uint64_t local_id() const { return local_id_; } - void set_local_id(uint64_t id) { local_id_ = id; } + void set_local_id(uint64_t id); uintptr_t magic = DEV_MAGIC; @@ -140,6 +145,18 @@ struct zx_device : fbl::RefCountedUpgradeable<zx_device>, fbl::Recyclable<zx_dev char name[ZX_DEVICE_NAME_MAX + 1] = {}; + // Trait structures for the local ID map + struct LocalIdNode { + static fbl::WAVLTreeNodeState<fbl::RefPtr<zx_device>>& node_state(zx_device& obj) { + return obj.local_id_node_; + } + }; + struct LocalIdKeyTraits { + static uint64_t GetKey(const zx_device& obj) { return obj.local_id_; } + static bool LessThan(const uint64_t& key1, const uint64_t& key2) { return key1 < key2; } + static bool EqualTo (const uint64_t& key1, const uint64_t& key2) { return key1 == key2; } + }; + private: zx_device() = default; @@ -162,6 +179,8 @@ private: } } + fbl::WAVLTreeNodeState<fbl::RefPtr<zx_device>> local_id_node_; + // Identifier assigned by devmgr that can be used to assemble composite // devices. uint64_t local_id_ = 0; diff --git a/zircon/system/core/devmgr/devhost/zx-device.cpp b/zircon/system/core/devmgr/devhost/zx-device.cpp index e2d632a0534107319848cdc8b1d47ca98b3d3ded..97fe5c4b76d1e5c4a62649897eca67fde6d47760 100644 --- a/zircon/system/core/devmgr/devhost/zx-device.cpp +++ b/zircon/system/core/devmgr/devhost/zx-device.cpp @@ -6,6 +6,8 @@ #include "devhost.h" #include <fbl/auto_call.h> +#include <fbl/auto_lock.h> +#include <fbl/mutex.h> zx_status_t zx_device::Create(fbl::RefPtr<zx_device>* out_dev) { *out_dev = fbl::AdoptRef(new zx_device()); @@ -58,3 +60,32 @@ void zx_device::fbl_recycle() TA_NO_THREAD_SAFETY_ANALYSIS { devmgr::devhost_finalize(); } } + +static fbl::Mutex local_id_map_lock_; +static fbl::WAVLTree<uint64_t, fbl::RefPtr<zx_device>, zx_device::LocalIdKeyTraits, + zx_device::LocalIdNode> local_id_map_ TA_GUARDED(local_id_map_lock_); + +void zx_device::set_local_id(uint64_t id) { + // If this is the last reference, we want it to go away outside of the lock + fbl::RefPtr<zx_device> old_entry; + + fbl::AutoLock guard(&local_id_map_lock_); + if (local_id_ != 0) { + old_entry = local_id_map_.erase(*this); + ZX_ASSERT(old_entry.get() == this); + } + + local_id_ = id; + if (id != 0) { + local_id_map_.insert(fbl::WrapRefPtr(this)); + } +} + +fbl::RefPtr<zx_device> zx_device::GetDeviceFromLocalId(uint64_t local_id) { + fbl::AutoLock guard(&local_id_map_lock_); + auto itr = local_id_map_.find(local_id); + if (itr == local_id_map_.end()) { + return nullptr; + } + return fbl::WrapRefPtr(&*itr); +} diff --git a/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl b/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl index 072a17ec36680675231c6f2fb57a3aab9461d5fd..9352532c974b4c022d44888225b0bff4eeb38059 100644 --- a/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl +++ b/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl @@ -114,6 +114,19 @@ protocol Controller { /// Ask the devhost to remove this device. On success, the remote end of /// this interface channel will close instead of returning a result. RemoveDevice(); + + /// Introduce a composite device that has the given name and properties. + /// |components| will be a list of all of the composite's components, + /// described using devhost local device ids. The order of the components + /// will match the original composite creation request. The new device will + /// communicate with devcoordinator via |rpc|. + /// + /// |local_device_id| will be a unique value within the device's devhost, identifying + /// the resulting composite device. + CreateCompositeDevice(handle<channel> rpc, + vector<LocalDeviceId>:COMPONENTS_MAX components, + string:DEVICE_NAME_MAX name, LocalDeviceId local_device_id) + -> (zx.status status); }; /// Interface for the devices in devhosts to coordinate with the devcoordinator.