blob: 2b589edd196bacf176cbed3c272ec0a58fdcebf4 [file] [log] [blame]
// Copyright 2022 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 <fidl/fuchsia.driver.transport.test/cpp/driver/wire.h>
#include <fidl/fuchsia.driver.transport.test/cpp/markers.h>
#include <fidl/fuchsia.driver.transport.test/cpp/wire.h>
#include <lib/ddk/binding_driver.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/fdf/dispatcher.h>
#include <lib/fidl/cpp/wire/arena.h>
#include <lib/fidl/cpp/wire/connect_service.h>
#include <lib/fidl_driver/cpp/wire_messaging_declarations.h>
#include <ddktl/device.h>
namespace fdtt = fuchsia_driver_transport_test;
class Device;
using DeviceType =
ddk::Device<Device, ddk::Unbindable, ddk::Messageable<fdtt::TestDeviceChild>::Mixin>;
class Device : public DeviceType {
public:
static zx_status_t Bind(void* ctx, zx_device_t* device);
Device(zx_device_t* parent, fdf::ClientEnd<fdtt::DriverTransportProtocol> client,
fdf_dispatcher_t* dispatcher)
: DeviceType(parent), client_(std::move(client), dispatcher) {}
// fdtt::TestDeviceChild protocol implementation.
void GetParentDataOverDriverTransport(
GetParentDataOverDriverTransportCompleter::Sync& completer) override;
// Device protocol implementation.
void DdkUnbind(ddk::UnbindTxn txn) { txn.Reply(); }
void DdkRelease() { delete this; }
private:
fdf::WireSharedClient<fdtt::DriverTransportProtocol> client_;
};
void Device::GetParentDataOverDriverTransport(
GetParentDataOverDriverTransportCompleter::Sync& completer) {
fdf::Arena arena('TDAT');
// Send a request to the parent driver over the driver transport.
client_.buffer(std::move(arena))
->TransmitData()
.ThenExactlyOnce(
[completer = completer.ToAsync()](
fdf::WireUnownedResult<fdtt::DriverTransportProtocol::TransmitData>& result) mutable {
if (!result.ok()) {
zxlogf(ERROR, "%s", result.FormatDescription().c_str());
completer.ReplyError(result.status());
return;
}
if (result->is_error()) {
zxlogf(ERROR, "TransmitData failed with status: %d", result->error_value());
completer.ReplyError(result->error_value());
return;
}
// Reply to the test's fidl request with the data.
completer.ReplySuccess(result->value()->out);
});
}
// static
zx_status_t Device::Bind(void* ctx, zx_device_t* device) {
// Connect to our parent driver.
auto client_end = DdkConnectRuntimeProtocol<fdtt::Service::DriverTransportProtocol>(device);
if (client_end.is_error()) {
zxlogf(ERROR, "DdkConnectRuntimeProtocol Failed =(");
return client_end.status_value();
}
auto* dispatcher = fdf_dispatcher_get_current_dispatcher();
auto dev = std::make_unique<Device>(device, std::move(*client_end), dispatcher);
zx_status_t status = dev->DdkAdd("child");
if (status == ZX_OK) {
// devmgr is now in charge of the memory for dev
[[maybe_unused]] auto ptr = dev.release();
}
return status;
}
static zx_driver_ops_t kDriverOps = []() -> zx_driver_ops_t {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.bind = Device::Bind;
return ops;
}();
ZIRCON_DRIVER(driver_transport_test_child, kDriverOps, "zircon", "0.1");