blob: 7b24f17891d3244e85dbffc922c851ec87372687 [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/binding.h>
#include <fbl/array.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/string.h>
#include <fbl/string_piece.h>
#include <fuchsia/device/manager/c/fidl.h>
#include <memory>
namespace devmgr {
// Forward declaration
class CompositeDevice;
class Coordinator;
struct Device;
// Describes a device on the path to a component of a composite device
struct ComponentPartDescriptor {
fbl::Array<const zx_bind_inst_t> match_program;
};
// A single device that is part of a composite device.
// TODO(teisenbe): Should this just be an inner-class of CompositeDevice?
class CompositeDeviceComponent {
public:
CompositeDeviceComponent(CompositeDevice* composite, uint32_t index,
fbl::Array<const ComponentPartDescriptor> parts);
CompositeDeviceComponent(CompositeDeviceComponent&&) = delete;
CompositeDeviceComponent& operator=(CompositeDeviceComponent&&) = delete;
CompositeDeviceComponent(const CompositeDeviceComponent&) = delete;
CompositeDeviceComponent& operator=(const CompositeDeviceComponent&) = delete;
~CompositeDeviceComponent();
// Attempt to match this component against |dev|. Returns true if the match
// was successful.
bool TryMatch(const fbl::RefPtr<Device>& dev);
// Bind this component to the given device.
zx_status_t Bind(const fbl::RefPtr<Device>& dev);
// Unbind this component.
void Unbind();
uint32_t index() const { return index_; }
CompositeDevice* composite() const { return composite_; }
// If not nullptr, this component has been bound to this device
const fbl::RefPtr<Device>& bound_device() const { return bound_device_; }
const fbl::RefPtr<Device>& component_device() const { return component_device_; }
// Registers (or unregisters) the component device (i.e. an instance of the
// "component" driver) that bound to bound_device().
void set_component_device(fbl::RefPtr<Device> device) {
component_device_ = std::move(device);
}
// Used for embedding a component in the CompositeDevice's bound and unbound
// lists.
struct Node {
static fbl::DoublyLinkedListNodeState<std::unique_ptr<CompositeDeviceComponent>>&
node_state(CompositeDeviceComponent& obj) { return obj.node_; }
};
private:
// The CompositeDevice that this is a part of
CompositeDevice* const composite_;
// The index of this component within its CompositeDevice
const uint32_t index_;
// A description of the devices from the root of the tree to the component
// itself.
const fbl::Array<const ComponentPartDescriptor> parts_;
// If this component has been bound to a device, this points to that device.
fbl::RefPtr<Device> bound_device_ = nullptr;
// Once the bound device has the component driver attach to it, this points
// to the device managed by the component driver.
fbl::RefPtr<Device> component_device_ = nullptr;
fbl::DoublyLinkedListNodeState<std::unique_ptr<CompositeDeviceComponent>> node_;
};
// A device composed of other devices.
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 components_count, uint32_t coresident_device_index);
CompositeDevice(CompositeDevice&&) = delete;
CompositeDevice& operator=(CompositeDevice&&) = delete;
CompositeDevice(const CompositeDevice&) = delete;
CompositeDevice& operator=(const CompositeDevice&) = delete;
~CompositeDevice();
static zx_status_t Create(const fbl::StringPiece& name,
const zx_device_prop_t* props_data, size_t props_count,
const fuchsia_device_manager_DeviceComponent* components,
size_t components_count, uint32_t coresident_device_index,
std::unique_ptr<CompositeDevice>* out);
const fbl::String& name() const {
return name_;
}
const fbl::Array<const zx_device_prop_t>& properties() const {
return properties_;
}
uint32_t components_count() const { return components_count_; }
// Returns a reference to the constructed composite device, if it exists.
fbl::RefPtr<Device> device() const {
return device_;
}
// 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
// the matching component.
bool TryMatchComponents(const fbl::RefPtr<Device>& dev, size_t* index_out);
// Bind the component with the given index to the specified device
zx_status_t BindComponent(size_t index, const fbl::RefPtr<Device>& dev);
// Mark the given component as unbound. Note that since we don't expose
// this device's components in the API, this method can only be invoked by
// CompositeDeviceComponent
void UnbindComponent(CompositeDeviceComponent* component);
// Creates the actual device and orchestrates the creation of the composite
// device in a devhost.
// Returns ZX_ERR_SHOULD_WAIT if some component is not fully ready (i.e. has
// either not been matched or the component driver that bound to it has not
// yet published its device).
zx_status_t TryAssemble();
// Forget about the composite device that was constructed. If TryAssemble()
// is invoked after this, it will reassemble the device.
void Remove();
// Node for list of composite devices the coordinator knows about
struct Node {
static fbl::DoublyLinkedListNodeState<std::unique_ptr<CompositeDevice>>&
node_state(CompositeDevice& obj) { return obj.node_; }
};
using ComponentList = fbl::DoublyLinkedList<std::unique_ptr<CompositeDeviceComponent>,
CompositeDeviceComponent::Node>;
ComponentList& bound_components() { return bound_; }
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_;
ComponentList bound_;
fbl::DoublyLinkedListNodeState<std::unique_ptr<CompositeDevice>> node_;
// Once the composite has been assembled, this refers to the constructed
// device.
fbl::RefPtr<Device> device_;
};
} // namespace devmgr