| // 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/device.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/zx/channel.h> |
| |
| #include "metadata.h" |
| |
| namespace devmgr { |
| |
| class Coordinator; |
| class Devhost; |
| struct Devnode; |
| class SuspendContext; |
| |
| class PendingOperation { |
| public: |
| enum class Op : uint32_t { |
| kBind = 1, |
| kSuspend = 2, |
| }; |
| |
| PendingOperation(Op op, SuspendContext* context) : op_(op), context_(context) {} |
| |
| struct Node { |
| static fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>>& node_state( |
| PendingOperation& obj) { |
| return obj.node_; |
| } |
| }; |
| |
| Op op() const { return op_; } |
| SuspendContext* context() const { return context_; } |
| |
| private: |
| fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>> node_; |
| |
| Op op_; |
| SuspendContext* context_; |
| }; |
| |
| struct Device { |
| explicit Device(Coordinator* coord); |
| ~Device(); |
| |
| // Begins waiting in |dispatcher| on |dev->wait|. This transfers a |
| // reference of |dev| to the dispatcher. The dispatcher returns ownership |
| // when the of that reference when the handler is invoked. |
| // TODO(teisenbe/kulakowski): Make this take a RefPtr |
| static zx_status_t BeginWait(Device* dev, async_dispatcher_t* dispatcher) { |
| // TODO(teisenbe/kulakowski): Once this takes a refptr, we should leak a |
| // ref in the success case (to present the ref owned by the dispatcher). |
| return dev->wait.Begin(dispatcher); |
| } |
| |
| // Entrypoint for the RPC handler that captures the pointer ownership |
| // semantics. |
| void HandleRpcEntry(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, |
| const zx_packet_signal_t* signal) { |
| // TODO(teisenbe/kulakowski): Perform the appropriate dance to construct |
| // a RefPtr from |this| without a net-increase in refcount, to represent |
| // the dispatcher passing ownership of its reference to the handler |
| HandleRpc(this, dispatcher, wait, status, signal); |
| } |
| |
| // TODO(teisenbe/kulakowski): Make this take a RefPtr |
| static void HandleRpc(Device* dev, async_dispatcher_t* dispatcher, |
| async::WaitBase* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| Coordinator* coordinator; |
| zx::channel hrpc; |
| uint32_t flags = 0; |
| |
| async::WaitMethod<Device, &Device::HandleRpcEntry> wait{this}; |
| async::TaskClosure publish_task; |
| |
| Devhost* host = nullptr; |
| const char* name = nullptr; |
| const char* libname = nullptr; |
| fbl::unique_ptr<const char[]> args; |
| // The backoff between each driver retry. This grows exponentially. |
| zx::duration backoff = zx::msec(250); |
| // The number of retries left for the driver. |
| uint32_t retries = 4; |
| mutable int32_t refcount_ = 0; |
| uint32_t protocol_id = 0; |
| uint32_t prop_count = 0; |
| Devnode* self = nullptr; |
| Devnode* link = nullptr; |
| Device* parent = nullptr; |
| Device* proxy = nullptr; |
| |
| // For attaching as an open connection to the proxy device, |
| // or once the device becomes visible. |
| zx::channel client_remote; |
| |
| // listnode for this device in its parent's |
| // list-of-children |
| fbl::DoublyLinkedListNodeState<Device*> node; |
| struct Node { |
| static fbl::DoublyLinkedListNodeState<Device*>& node_state( |
| Device& obj) { |
| return obj.node; |
| } |
| }; |
| |
| // listnode for this device in its devhost's |
| // list-of-devices |
| fbl::DoublyLinkedListNodeState<Device*> dhnode; |
| struct DevhostNode { |
| static fbl::DoublyLinkedListNodeState<Device*>& node_state( |
| Device& obj) { |
| return obj.dhnode; |
| } |
| }; |
| |
| // list of all child devices of this device |
| fbl::DoublyLinkedList<Device*, Node> children; |
| |
| // list of outstanding requests from the devcoord |
| // to this device's devhost, awaiting a response |
| fbl::DoublyLinkedList<fbl::unique_ptr<PendingOperation>, PendingOperation::Node> pending; |
| |
| // listnode for this device in the all devices list |
| fbl::DoublyLinkedListNodeState<Device*> anode; |
| struct AllDevicesNode { |
| static fbl::DoublyLinkedListNodeState<Device*>& node_state( |
| Device& obj) { |
| return obj.anode; |
| } |
| }; |
| |
| // Metadata entries associated to this device. |
| fbl::DoublyLinkedList<fbl::unique_ptr<Metadata>, Metadata::Node> metadata; |
| |
| fbl::unique_ptr<zx_device_prop_t[]> props; |
| |
| // Allocation backing |name| and |libname| |
| fbl::unique_ptr<char[]> name_alloc_; |
| |
| // The AddRef and Release functions follow the contract for fbl::RefPtr. |
| void AddRef() const { |
| ++refcount_; |
| } |
| |
| // Returns true when the last reference has been released. |
| bool Release() const { |
| const int32_t rc = refcount_; |
| --refcount_; |
| return rc == 1; |
| } |
| }; |
| |
| } // namespace devmgr |