blob: 1f8239233ef21c091789ccb6a3d944066d9598cd [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.
#ifndef SRC_DEVICES_GPIO_DRIVERS_GPIO_GPIO_H_
#define SRC_DEVICES_GPIO_DRIVERS_GPIO_GPIO_H_
#include <fidl/fuchsia.hardware.gpio/cpp/wire.h>
#include <fidl/fuchsia.hardware.gpioimpl/cpp/driver/wire.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/ddk/platform-defs.h>
#include <optional>
#include <string_view>
#include <ddk/metadata/gpio.h>
#include <ddktl/device.h>
#include <ddktl/fidl.h>
namespace gpio {
class GpioDevice;
using GpioDeviceType =
ddk::Device<GpioDevice, ddk::Messageable<fuchsia_hardware_gpio::Gpio>::Mixin, ddk::Unbindable>;
class GpioRootDevice;
using GpioRootDeviceType = ddk::Device<GpioRootDevice, ddk::Unbindable>;
class GpioRootDevice : public GpioRootDeviceType {
public:
static zx_status_t Create(void* ctx, zx_device_t* parent);
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
private:
explicit GpioRootDevice(zx_device_t* parent)
: GpioRootDeviceType(parent), driver_dispatcher_(fdf::Dispatcher::GetCurrent()) {}
zx_status_t AddPinDevices(uint32_t controller_id, const std::vector<gpio_pin_t>& pins);
void DispatcherShutdownHandler(fdf_dispatcher_t* dispatcher);
const fdf::UnownedDispatcher driver_dispatcher_;
std::optional<fdf::SynchronizedDispatcher> fidl_dispatcher_;
std::optional<ddk::UnbindTxn> unbind_txn_;
};
// GpioDevice instances live on fidl_dispatcher_, which is either a dispatcher owned by the
// GpioRootDevice, or the default driver dispatcher. Driver hooks (DdkUnbind and DdkRelease) always
// run on the default driver dispatcher.
class GpioDevice : public GpioDeviceType {
public:
GpioDevice(zx_device_t* parent, fdf::UnownedDispatcher fidl_dispatcher,
fdf::ClientEnd<fuchsia_hardware_gpioimpl::GpioImpl> gpio, uint32_t pin,
uint32_t controller_id, std::string_view name)
: GpioDeviceType(parent),
fidl_dispatcher_(std::move(fidl_dispatcher)),
pin_(pin),
controller_id_(controller_id),
name_(name),
gpio_(std::in_place, std::move(gpio), fidl_dispatcher_->get()),
bindings_(std::in_place),
outgoing_(std::in_place, fidl_dispatcher_->async_dispatcher()) {}
zx_status_t InitAddDevice();
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
private:
void GetPin(GetPinCompleter::Sync& completer) override;
void GetName(GetNameCompleter::Sync& completer) override;
void ConfigIn(ConfigInRequestView request, ConfigInCompleter::Sync& completer) override;
void ConfigOut(ConfigOutRequestView request, ConfigOutCompleter::Sync& completer) override;
void Read(ReadCompleter::Sync& completer) override;
void Write(WriteRequestView request, WriteCompleter::Sync& completer) override;
void SetDriveStrength(SetDriveStrengthRequestView request,
SetDriveStrengthCompleter::Sync& completer) override;
void GetDriveStrength(GetDriveStrengthCompleter::Sync& completer) override;
void GetInterrupt(GetInterruptRequestView request,
GetInterruptCompleter::Sync& completer) override;
void ReleaseInterrupt(ReleaseInterruptCompleter::Sync& completer) override;
void SetAltFunction(SetAltFunctionRequestView request,
SetAltFunctionCompleter::Sync& completer) override;
void SetPolarity(SetPolarityRequestView request, SetPolarityCompleter::Sync& completer) override;
private:
const fdf::UnownedDispatcher fidl_dispatcher_;
const uint32_t pin_;
const uint32_t controller_id_;
const std::string name_;
// These objects can only be accessed on the FIDL dispatcher. Making them optional allows them to
// be destroyed manually in our unbind hook.
std::optional<fdf::WireClient<fuchsia_hardware_gpioimpl::GpioImpl>> gpio_;
std::optional<fidl::ServerBindingGroup<fuchsia_hardware_gpio::Gpio>> bindings_;
std::optional<component::OutgoingDirectory> outgoing_;
};
class GpioInitDevice;
using GpioInitDeviceType = ddk::Device<GpioInitDevice>;
class GpioInitDevice : public GpioInitDeviceType {
public:
static void Create(zx_device_t* parent, fdf::ClientEnd<fuchsia_hardware_gpioimpl::GpioImpl> gpio,
uint32_t controller_id);
explicit GpioInitDevice(zx_device_t* parent) : GpioInitDeviceType(parent) {}
void DdkRelease() { delete this; }
private:
static zx_status_t ConfigureGpios(const fuchsia_hardware_gpioimpl::wire::InitMetadata& metadata,
fdf::WireSyncClient<fuchsia_hardware_gpioimpl::GpioImpl> gpio);
};
} // namespace gpio
#endif // SRC_DEVICES_GPIO_DRIVERS_GPIO_GPIO_H_