// Copyright 2020 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 "devfs_vnode.h"

#include <ddk/device.h>
#include <fbl/string_buffer.h>
#include <fs/vfs_types.h>

#include "driver_host.h"

namespace {

namespace power_fidl = ::llcpp::fuchsia::hardware::power;

// The path might get truncated if too long, which isn't a problem because it should just result in
// the driver not being found.
fbl::StringBuffer<fuchsia_device_MAX_DRIVER_PATH_LEN> GetFullDriverPath(
    const fidl::StringView& driver_path) {
  fbl::StringBuffer<fuchsia_device_MAX_DRIVER_PATH_LEN> buffer;
  if (!driver_path.empty() && driver_path[0] != '/') {
    buffer.Append(fbl::StringPiece(internal::ContextForApi()->root_driver_path()));
  }
  return buffer.Append(driver_path.data(), driver_path.size());
}

}  // namespace

zx_status_t DevfsVnode::Open(fs::Vnode::ValidatedOptions options,
                             fbl::RefPtr<Vnode>* out_redirect) {
  if (dev_->Unbound()) {
    return ZX_ERR_IO_NOT_PRESENT;
  }
  fbl::RefPtr<zx_device_t> new_dev;
  zx_status_t status = device_open(dev_, &new_dev, options->ToIoV1Flags());
  if (status != ZX_OK) {
    return status;
  }
  if (new_dev != dev_) {
    *out_redirect = new_dev->vnode;
  }
  return ZX_OK;
}

zx_status_t DevfsVnode::Close() {
  zx_status_t status = device_close(dev_, 0);
  // If this vnode is for an instance device, drop its reference on close to break
  // the reference cycle.  This is handled for non-instance devices during the device
  // remove path.
  if (dev_->flags() & DEV_FLAG_INSTANCE) {
    dev_->vnode.reset();
  }
  return status;
}

zx_status_t DevfsVnode::GetAttributes(fs::VnodeAttributes* a) {
  a->mode = V_TYPE_CDEV | V_IRUSR | V_IWUSR;
  a->content_size = dev_->GetSizeOp();
  a->link_count = 1;
  return ZX_OK;
}

fs::VnodeProtocolSet DevfsVnode::GetProtocols() const { return fs::VnodeProtocol::kDevice; }

zx_status_t DevfsVnode::GetNodeInfoForProtocol(fs::VnodeProtocol protocol, fs::Rights rights,
                                               fs::VnodeRepresentation* info) {
  if (protocol == fs::VnodeProtocol::kDevice) {
    zx::eventpair event;
    if (dev_->event.is_valid()) {
      zx_status_t status = dev_->event.duplicate(ZX_RIGHTS_BASIC, &event);
      if (status != ZX_OK) {
        return status;
      }
    }
    *info = fs::VnodeRepresentation::Device{std::move(event)};
    return ZX_OK;
  }
  return ZX_ERR_NOT_SUPPORTED;
}

void DevfsVnode::HandleFsSpecificMessage(fidl_incoming_msg_t* msg, fidl::Transaction* txn) {
  if (dev_->Unbound()) {
    txn->Close(ZX_ERR_IO_NOT_PRESENT);
    return;
  }
  ::fidl::DispatchResult dispatch_result =
      llcpp::fuchsia::device::Controller::TryDispatch(this, msg, txn);
  if (dispatch_result == ::fidl::DispatchResult::kFound) {
    return;
  }

  auto ddk_txn = MakeDdkInternalTransaction(txn);
  zx_status_t status = dev_->MessageOp(msg, ddk_txn.Txn());
  if (status != ZX_OK && status != ZX_ERR_ASYNC) {
    // Close the connection on any error
    txn->Close(status);
  }
}

zx_status_t DevfsVnode::Read(void* data, size_t len, size_t off, size_t* out_actual) {
  if (dev_->Unbound()) {
    return ZX_ERR_IO_NOT_PRESENT;
  }
  return dev_->ReadOp(data, len, off, out_actual);
}
zx_status_t DevfsVnode::Write(const void* data, size_t len, size_t off, size_t* out_actual) {
  if (dev_->Unbound()) {
    return ZX_ERR_IO_NOT_PRESENT;
  }
  return dev_->WriteOp(data, len, off, out_actual);
}

void DevfsVnode::Bind(::fidl::StringView driver, BindCompleter::Sync& completer) {
  zx_status_t status = device_bind(dev_, GetFullDriverPath(driver).c_str());
  if (status != ZX_OK) {
    completer.ReplyError(status);
  } else {
    dev_->set_bind_conn([completer = completer.ToAsync()](zx_status_t status) mutable {
      if (status != ZX_OK) {
        completer.ReplyError(status);
      } else {
        completer.ReplySuccess();
      }
    });
  }
};

void DevfsVnode::GetDevicePerformanceStates(GetDevicePerformanceStatesCompleter::Sync& completer) {
  auto& perf_states = dev_->GetPerformanceStates();
  ZX_DEBUG_ASSERT(perf_states.size() == fuchsia_device_MAX_DEVICE_PERFORMANCE_STATES);

  ::fidl::Array<::llcpp::fuchsia::device::DevicePerformanceStateInfo, 20> states{};
  for (size_t i = 0; i < fuchsia_device_MAX_DEVICE_PERFORMANCE_STATES; i++) {
    states[i] = perf_states[i];
  }
  completer.Reply(states, ZX_OK);
}

void DevfsVnode::GetCurrentPerformanceState(GetCurrentPerformanceStateCompleter::Sync& completer) {
  completer.Reply(dev_->current_performance_state());
}

void DevfsVnode::Rebind(::fidl::StringView driver, RebindCompleter::Sync& completer) {
  dev_->set_rebind_drv_name(GetFullDriverPath(driver).c_str());
  zx_status_t status = device_rebind(dev_.get());

  if (status != ZX_OK) {
    completer.ReplyError(status);
  } else {
    // These will be set, until device is unbound and then bound again.
    dev_->set_rebind_conn([completer = completer.ToAsync()](zx_status_t status) mutable {
      if (status != ZX_OK) {
        completer.ReplyError(status);
      } else {
        completer.ReplySuccess();
      }
    });
  }
}

void DevfsVnode::UnbindChildren(UnbindChildrenCompleter::Sync& completer) {
  zx_status_t status = device_schedule_unbind_children(dev_);

  if (status != ZX_OK) {
    completer.ReplyError(status);
  } else {
    // The unbind conn will be set until all the children of this device are unbound.
    dev_->set_unbind_children_conn([completer = completer.ToAsync()](zx_status_t status) mutable {
      if (status != ZX_OK) {
        completer.ReplyError(status);
      } else {
        completer.ReplySuccess();
      }
    });
  }
}

void DevfsVnode::ScheduleUnbind(ScheduleUnbindCompleter::Sync& completer) {
  zx_status_t status = device_schedule_remove(dev_, true /* unbind_self */);
  if (status != ZX_OK) {
    completer.ReplyError(status);
  } else {
    completer.ReplySuccess();
  }
}

void DevfsVnode::GetDriverName(GetDriverNameCompleter::Sync& completer) {
  if (!dev_->driver) {
    completer.Reply(ZX_ERR_NOT_SUPPORTED, {});
    return;
  }
  const char* name = dev_->driver->name();
  if (name == nullptr) {
    name = "unknown";
  }
  completer.Reply(ZX_OK, fidl::unowned_str(name, strlen(name)));
}

void DevfsVnode::GetDeviceName(GetDeviceNameCompleter::Sync& completer) {
  completer.Reply(fidl::unowned_str(dev_->name(), strlen(dev_->name())));
}

void DevfsVnode::GetTopologicalPath(GetTopologicalPathCompleter::Sync& completer) {
  char buf[fuchsia_device_MAX_DEVICE_PATH_LEN + 1];
  size_t actual;
  zx_status_t status = dev_->driver_host_context()->GetTopoPath(dev_, buf, sizeof(buf), &actual);
  if (status != ZX_OK) {
    completer.ReplyError(status);
    return;
  }
  if (actual > 0) {
    // Remove the accounting for the null byte
    actual--;
  }
  auto path = ::fidl::StringView(buf, actual);
  completer.ReplySuccess(std::move(path));
}

void DevfsVnode::GetEventHandle(GetEventHandleCompleter::Sync& completer) {
  zx::eventpair event;
  zx_status_t status = dev_->event.duplicate(ZX_RIGHTS_BASIC, &event);
  static_assert(fuchsia_device_DEVICE_SIGNAL_READABLE == DEV_STATE_READABLE);
  static_assert(fuchsia_device_DEVICE_SIGNAL_WRITABLE == DEV_STATE_WRITABLE);
  static_assert(fuchsia_device_DEVICE_SIGNAL_ERROR == DEV_STATE_ERROR);
  static_assert(fuchsia_device_DEVICE_SIGNAL_HANGUP == DEV_STATE_HANGUP);
  static_assert(fuchsia_device_DEVICE_SIGNAL_OOB == DEV_STATE_OOB);
  // TODO(teisenbe): The FIDL definition erroneously describes this as an event rather than
  // eventpair.
  completer.Reply(status, zx::event(event.release()));
}

void DevfsVnode::GetDriverLogFlags(GetDriverLogFlagsCompleter::Sync& completer) {
  if (!dev_->driver) {
    completer.Reply(ZX_ERR_UNAVAILABLE, 0);
    return;
  }
  uint32_t flags = dev_->driver->driver_rec()->log_flags;
  completer.Reply(ZX_OK, flags);
}

void DevfsVnode::SetDriverLogFlags(uint32_t clear_flags, uint32_t set_flags,
                                   SetDriverLogFlagsCompleter::Sync& completer) {
  if (!dev_->driver) {
    completer.Reply(ZX_ERR_UNAVAILABLE);
    return;
  }
  uint32_t flags = dev_->driver->driver_rec()->log_flags;
  flags &= ~clear_flags;
  flags |= set_flags;
  dev_->driver->driver_rec()->log_flags = flags;
  completer.Reply(ZX_OK);
}

void DevfsVnode::RunCompatibilityTests(int64_t hook_wait_time,
                                       RunCompatibilityTestsCompleter::Sync& completer) {
  zx_status_t status = device_run_compatibility_tests(dev_, hook_wait_time);
  if (status == ZX_OK) {
    dev_->PushTestCompatibilityConn(
        [completer = completer.ToAsync()](zx_status_t status) mutable { completer.Reply(status); });
  } else {
    completer.Reply(status);
  }
};

void DevfsVnode::GetDevicePowerCaps(GetDevicePowerCapsCompleter::Sync& completer) {
  // For now, the result is always a successful response because the device itself is not added
  // without power states validation. In future, we may add more checks for validation, and the
  // error result will be put to use.
  ::llcpp::fuchsia::device::Controller_GetDevicePowerCaps_Response response{};
  auto& states = dev_->GetPowerStates();

  ZX_DEBUG_ASSERT(states.size() == fuchsia_device_MAX_DEVICE_POWER_STATES);
  for (size_t i = 0; i < fuchsia_device_MAX_DEVICE_POWER_STATES; i++) {
    response.dpstates[i] = states[i];
  }
  completer.Reply(::llcpp::fuchsia::device::Controller_GetDevicePowerCaps_Result::WithResponse(
      fidl::unowned_ptr(&response)));
};

void DevfsVnode::SetPerformanceState(uint32_t requested_state,
                                     SetPerformanceStateCompleter::Sync& completer) {
  uint32_t out_state;
  zx_status_t status =
      dev_->driver_host_context()->DeviceSetPerformanceState(dev_, requested_state, &out_state);
  completer.Reply(status, out_state);
}

void DevfsVnode::ConfigureAutoSuspend(bool enable,
                                      ::llcpp::fuchsia::device::DevicePowerState requested_state,
                                      ConfigureAutoSuspendCompleter::Sync& completer) {
  zx_status_t status =
      dev_->driver_host_context()->DeviceConfigureAutoSuspend(dev_, enable, requested_state);
  completer.Reply(status);
}

void DevfsVnode::UpdatePowerStateMapping(
    ::fidl::Array<::llcpp::fuchsia::device::SystemPowerStateInfo,
                  power_fidl::statecontrol::MAX_SYSTEM_POWER_STATES>
        mapping,
    UpdatePowerStateMappingCompleter::Sync& completer) {
  std::array<::llcpp::fuchsia::device::SystemPowerStateInfo,
             power_fidl::statecontrol::MAX_SYSTEM_POWER_STATES>
      states_mapping;

  for (size_t i = 0; i < power_fidl::statecontrol::MAX_SYSTEM_POWER_STATES; i++) {
    states_mapping[i] = mapping[i];
  }
  zx_status_t status = dev_->SetSystemPowerStateMapping(states_mapping);
  if (status != ZX_OK) {
    completer.ReplyError(status);
    return;
  }

  fidl::aligned<::llcpp::fuchsia::device::Controller_UpdatePowerStateMapping_Response> response;
  completer.Reply(::llcpp::fuchsia::device::Controller_UpdatePowerStateMapping_Result::WithResponse(
      fidl::unowned_ptr(&response)));
}

void DevfsVnode::GetPowerStateMapping(GetPowerStateMappingCompleter::Sync& completer) {
  ::llcpp::fuchsia::device::Controller_GetPowerStateMapping_Response response;

  auto& mapping = dev_->GetSystemPowerStateMapping();
  ZX_DEBUG_ASSERT(mapping.size() == power_fidl::statecontrol::MAX_SYSTEM_POWER_STATES);

  for (size_t i = 0; i < power_fidl::statecontrol::MAX_SYSTEM_POWER_STATES; i++) {
    response.mapping[i] = mapping[i];
  }
  completer.Reply(::llcpp::fuchsia::device::Controller_GetPowerStateMapping_Result::WithResponse(
      fidl::unowned_ptr(&response)));
};

void DevfsVnode::Suspend(::llcpp::fuchsia::device::DevicePowerState requested_state,
                         SuspendCompleter::Sync& completer) {
  dev_->suspend_cb = [completer = completer.ToAsync()](zx_status_t status,
                                                       uint8_t out_state) mutable {
    completer.Reply(status, static_cast<::llcpp::fuchsia::device::DevicePowerState>(out_state));
  };
  dev_->driver_host_context()->DeviceSuspendNew(dev_, requested_state);
}

void DevfsVnode::Resume(ResumeCompleter::Sync& completer) {
  dev_->resume_cb = [completer = completer.ToAsync()](zx_status_t status, uint8_t out_power_state,
                                                      uint32_t out_perf_state) mutable {
    completer.Reply(status,
                    static_cast<::llcpp::fuchsia::device::DevicePowerState>(out_power_state),
                    out_perf_state);
  };
  dev_->driver_host_context()->DeviceResumeNew(dev_);
}

namespace {

// Reply originating from driver.
zx_status_t DdkReply(fidl_txn_t* txn, const fidl_outgoing_msg_t* msg) {
  fidl::OutgoingMessage message(msg);

  // If FromDdkInternalTransaction returns a unique_ptr variant, it will be destroyed when exiting
  // this scope.
  auto fidl_txn = FromDdkInternalTransaction(ddk::internal::Transaction::FromTxn(txn));
  std::visit([&](auto&& arg) { arg->Reply(&message); }, fidl_txn);
  return ZX_OK;
}

// Bitmask for checking if a pointer stashed in a ddk::internal::Transaction is from the heap or
// not. This is safe to use on our pointers, because fidl::Transactions are always aligned to more
// than one byte.
static_assert(alignof(fidl::Transaction) > 1);
constexpr uintptr_t kTransactionIsBoxed = 0x1;

}  // namespace

ddk::internal::Transaction MakeDdkInternalTransaction(fidl::Transaction* txn) {
  device_fidl_txn_t fidl_txn = {};
  fidl_txn.txn = {
      .reply = DdkReply,
  };
  fidl_txn.driver_host_context = reinterpret_cast<uintptr_t>(txn);
  return ddk::internal::Transaction(fidl_txn);
}

ddk::internal::Transaction MakeDdkInternalTransaction(std::unique_ptr<fidl::Transaction> txn) {
  device_fidl_txn_t fidl_txn = {};
  fidl_txn.txn = {
      .reply = DdkReply,
  };
  fidl_txn.driver_host_context = reinterpret_cast<uintptr_t>(txn.release()) | kTransactionIsBoxed;
  return ddk::internal::Transaction(fidl_txn);
}

std::variant<fidl::Transaction*, std::unique_ptr<fidl::Transaction>> FromDdkInternalTransaction(
    ddk::internal::Transaction* txn) {
  uintptr_t raw = txn->DriverHostCtx();
  ZX_ASSERT_MSG(raw != 0, "Reused a fidl_txn_t!\n");

  // Invalidate the source transaction
  txn->DeviceFidlTxn()->driver_host_context = 0;

  auto ptr = reinterpret_cast<fidl::Transaction*>(raw & ~kTransactionIsBoxed);
  if (raw & kTransactionIsBoxed) {
    return std::unique_ptr<fidl::Transaction>(ptr);
  }
  return ptr;
}
