blob: 854130adf4cdcefb44e098348944a8d08f86dec5 [file] [log] [blame]
// Copyright 2018 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 "src/devices/tests/sysdev/sysdev.h"
#include <fuchsia/boot/c/fidl.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
#include <zircon/boot/image.h>
#include <zircon/types.h>
#include <memory>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/platform-defs.h>
#include <ddktl/device.h>
#include "src/devices/tests/sysdev/sysdev-bind.h"
namespace {
class Sysdev;
using SysdevType = ddk::Device<Sysdev>;
class Sysdev : public SysdevType {
public:
explicit Sysdev(zx_device_t* device) : SysdevType(device) {}
static zx_status_t Create(void* ctx, zx_device_t* parent, const char* name, const char* args,
zx_handle_t items_svc_handle);
// Device protocol implementation.
void DdkRelease() {
// sysdev should never have its release called.
ZX_ASSERT_MSG(false, "Sysdev::DdkRelease() invoked!\n");
}
zx_status_t MakeComposite();
};
zx_status_t Sysdev::Create(void* ctx, zx_device_t* parent, const char* name, const char* args,
zx_handle_t items_svc_handle) {
zx::channel items_svc(items_svc_handle);
auto sysdev = std::make_unique<Sysdev>(parent);
// Check if we were sent configuration data
zx::vmo payload;
uint32_t payload_len = 0;
if (items_svc.is_valid()) {
zx_status_t status = fuchsia_boot_ItemsGet(items_svc.get(), ZBI_TYPE_DRV_BOARD_PRIVATE, 0,
payload.reset_and_get_address(), &payload_len);
if (status != ZX_OK) {
return status;
}
}
uintptr_t payload_addr = 0;
if (payload_len > 0) {
zx_status_t status =
zx::vmar::root_self()->map(ZX_VM_PERM_READ, 0, payload, 0, payload_len, &payload_addr);
if (status != ZX_OK) {
return status;
}
}
payload.reset();
zx_status_t status = sysdev->DdkAdd(ddk::DeviceAddArgs("sys").set_flags(DEVICE_ADD_NON_BINDABLE));
if (status != ZX_OK) {
return status;
}
// If we were sent configuration data, check to see if we were told to
// create a composite. If so, we will create a composite out of
// "well-known" devices that the test may create. These are children with
// the PLATFORM_DEV properties
// (PDEV_VID_TEST, PDEV_PID_LIBDRIVER_TEST, PDEV_DID_TEST_CHILD_1) and
// (PDEV_VID_TEST, PDEV_PID_LIBDRIVER_TEST, PDEV_DID_TEST_CHILD_2).
// The resulting composite will have PLATFORM_DEV properties
// (PDEV_VID_TEST, PDEV_PID_LIBDRIVER_TEST, PDEV_DID_TEST_COMPOSITE).
if (payload_len >= sizeof(bool)) {
auto should_create_composite = reinterpret_cast<const bool*>(payload_addr);
if (*should_create_composite) {
status = sysdev->MakeComposite();
ZX_ASSERT(status == ZX_OK);
}
}
// Now owned by devmgr.
__UNUSED auto ptr = sysdev.release();
return ZX_OK;
}
zx_status_t Sysdev::MakeComposite() {
// Composite binding rules for the well-known composite that
// libdriver-integration-test uses.
const zx_bind_inst_t root_match[] = {
BI_MATCH(),
};
const zx_bind_inst_t fragment1_match[] = {
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_TEST),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_LIBDRIVER_TEST),
BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_TEST_CHILD_1),
};
const zx_bind_inst_t fragment2_match[] = {
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_TEST),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_LIBDRIVER_TEST),
BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_TEST_CHILD_2),
};
const device_fragment_part_t fragment1[] = {
{countof(root_match), root_match},
{countof(fragment1_match), fragment1_match},
};
const device_fragment_part_t fragment2[] = {
{countof(root_match), root_match},
{countof(fragment2_match), fragment2_match},
};
const device_fragment_t fragments[] = {
{"fragment-1", countof(fragment1), fragment1},
{"fragment-2", countof(fragment2), fragment2},
};
const zx_device_prop_t props[] = {
{BIND_PLATFORM_DEV_VID, 0, PDEV_VID_TEST},
{BIND_PLATFORM_DEV_PID, 0, PDEV_PID_LIBDRIVER_TEST},
{BIND_PLATFORM_DEV_DID, 0, PDEV_DID_TEST_COMPOSITE},
};
const composite_device_desc_t comp_desc = {
.props = props,
.props_count = countof(props),
.fragments = fragments,
.fragments_count = countof(fragments),
.coresident_device_index = UINT32_MAX,
.metadata_list = nullptr,
.metadata_count = 0,
};
return device_add_composite(zxdev(), "composite", &comp_desc);
}
static constexpr zx_driver_ops_t driver_ops = []() {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.create = Sysdev::Create;
return ops;
}();
} // namespace
ZIRCON_DRIVER(test_sysdev, driver_ops, "zircon", "0.1");