blob: a39db45e6b46654b0a2e17b85b6576cc165fdde7 [file] [log] [blame]
// 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