// Copyright 2021 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/bin/driver_manager/bind_driver_manager.h"

#include <errno.h>
#include <lib/fit/function.h>
#include <zircon/status.h>

#include "src/devices/bin/driver_manager/binding_internal.h"
#include "src/devices/bin/driver_manager/devfs.h"
#include "src/devices/lib/log/log.h"

BindDriverManager::BindDriverManager(Coordinator* coordinator, AttemptBindFunc attempt_bind)
    : coordinator_(coordinator), attempt_bind_(std::move(attempt_bind)) {}

BindDriverManager::~BindDriverManager() {}

zx_status_t BindDriverManager::BindDriverToDevice(const MatchedDriver& driver,
                                                  const fbl::RefPtr<Device>& dev) {
  if (std::holds_alternative<MatchedCompositeDriverInfo>(driver)) {
    return BindDriverToFragment(std::get<MatchedCompositeDriverInfo>(driver), dev);
  }

  if (std::holds_alternative<MatchedDeviceGroupInfo>(driver)) {
    return BindDriverToDeviceGroup(std::get<MatchedDeviceGroupInfo>(driver), dev);
  }

  if (!std::holds_alternative<MatchedDriverInfo>(driver)) {
    return ZX_ERR_INTERNAL;
  }
  auto driver_info = std::get<MatchedDriverInfo>(driver);

  zx_status_t status = attempt_bind_(driver_info.driver, dev);

  // If we get this here it means we've successfully bound one driver
  // and the device isn't multi-bind.
  if (status == ZX_ERR_ALREADY_BOUND) {
    return ZX_OK;
  }

  if (status != ZX_OK) {
    LOGF(ERROR, "Failed to bind driver '%.*s' to device '%.*s': %s",
         static_cast<uint32_t>(driver_info.driver->libname.size()),
         driver_info.driver->libname.data(), static_cast<uint32_t>(dev->name().size()),
         dev->name().data(), zx_status_get_string(status));
  }
  return status;
}

zx_status_t BindDriverManager::BindDevice(const fbl::RefPtr<Device>& dev,
                                          std::string_view drvlibname, bool new_device) {
  // shouldn't be possible to get a bind request for a proxy device
  if (dev->flags & DEV_CTX_PROXY) {
    return ZX_ERR_NOT_SUPPORTED;
  }

  // A libname of "" means a general rebind request instead of a specific request.
  bool autobind = drvlibname.size() == 0;
  if (autobind && (dev->flags & DEV_CTX_SKIP_AUTOBIND)) {
    return ZX_OK;
  }

  // Attempt composite device matching first. This is unnecessary if a
  // specific driver has been requested.
  if (autobind) {
    for (auto& composite : coordinator_->device_manager()->composite_devices()) {
      auto status = composite.TryMatchBindFragments(dev);
      if (status != ZX_OK) {
        return status;
      }
    }
  }

  // TODO: disallow if we're in the middle of enumeration, etc
  zx::status<std::vector<MatchedDriver>> result = GetMatchingDrivers(dev, drvlibname);
  if (!result.is_ok()) {
    return result.error_value();
  }

  auto drivers = std::move(result.value());
  for (auto& driver : drivers) {
    zx_status_t status = BindDriverToDevice(driver, dev);
    if (status != ZX_OK) {
      return status;
    }
  }

  // Notify observers that this device is available again
  // Needed for non-auto-binding drivers like GPT against block, etc
  if (!new_device && autobind) {
    devfs_advertise_modified(dev);
  }

  return ZX_OK;
}

zx_status_t BindDriverManager::MatchDevice(const fbl::RefPtr<Device>& dev, const Driver* driver,
                                           bool autobind) const {
  if (dev->IsAlreadyBound()) {
    return ZX_ERR_ALREADY_BOUND;
  }

  if (autobind && dev->should_skip_autobind()) {
    return ZX_ERR_NEXT;
  }

  if (!dev->is_bindable() && !(dev->is_composite_bindable())) {
    return ZX_ERR_NEXT;
  }

  if (!can_driver_bind(driver, dev->protocol_id(), dev->props(), dev->str_props(), autobind)) {
    return ZX_ERR_NEXT;
  }

  return ZX_OK;
}

zx_status_t BindDriverManager::MatchAndBind(const fbl::RefPtr<Device>& dev, const Driver* drv,
                                            bool autobind) {
  zx_status_t status = MatchDevice(dev, drv, autobind);
  if (status != ZX_OK) {
    return status;
  }
  return BindDriverToDevice(MatchedDriverInfo{.driver = drv}, dev);
}

zx::status<std::vector<MatchedDriver>> BindDriverManager::GetMatchingDrivers(
    const fbl::RefPtr<Device>& dev, std::string_view drvlibname) {
  // It shouldn't be possible to get a bind request for a proxy device.
  if (dev->flags & DEV_CTX_PROXY) {
    return zx::error(ZX_ERR_NOT_SUPPORTED);
  }

  if (dev->IsAlreadyBound()) {
    return zx::error(ZX_ERR_ALREADY_BOUND);
  }

  std::vector<MatchedDriver> matched_drivers;

  // A libname of "" means a general rebind request
  // instead of a specific request
  bool autobind = drvlibname.size() == 0;

  // Check for drivers outside of the Driver-index.
  for (const Driver& driver : coordinator_->drivers()) {
    if (!autobind && drvlibname.compare(driver.libname)) {
      continue;
    }

    zx_status_t status = MatchDevice(dev, &driver, autobind);
    if (status == ZX_ERR_ALREADY_BOUND) {
      return zx::error(ZX_ERR_ALREADY_BOUND);
    }

    if (status == ZX_ERR_NEXT) {
      continue;
    }

    if (status == ZX_OK) {
      auto matched = MatchedDriverInfo{.driver = &driver};
      matched_drivers.push_back(std::move(matched));
    }

    // If the device doesn't support multibind (this is a devmgr-internal setting),
    // then return on first match or failure.
    // Otherwise, keep checking all the drivers.
    if (!(dev->flags & DEV_CTX_MULTI_BIND)) {
      if (status != ZX_OK) {
        return zx::error(status);
      }
      return zx::ok(std::move(matched_drivers));
    }
  }

  // Check for drivers in the Driver-index.
  {
    DriverLoader::MatchDeviceConfig config;
    config.libname = drvlibname;
    auto drivers = coordinator_->driver_loader().MatchDeviceDriverIndex(dev, config);
    for (auto driver : drivers) {
      matched_drivers.push_back(driver);
    }
  }

  return zx::ok(std::move(matched_drivers));
}

zx::status<std::vector<MatchedDriver>> BindDriverManager::MatchDeviceWithDriverIndex(
    const fbl::RefPtr<Device>& dev, const DriverLoader::MatchDeviceConfig& config) const {
  if (dev->IsAlreadyBound()) {
    return zx::error(ZX_ERR_ALREADY_BOUND);
  }

  if (dev->should_skip_autobind()) {
    return zx::error(ZX_ERR_NEXT);
  }

  if (!dev->is_bindable() && !(dev->is_composite_bindable())) {
    return zx::error(ZX_ERR_NEXT);
  }

  return zx::ok(coordinator_->driver_loader().MatchDeviceDriverIndex(dev, config));
}

zx_status_t BindDriverManager::MatchAndBindWithDriverIndex(
    const fbl::RefPtr<Device>& dev, const DriverLoader::MatchDeviceConfig& config) {
  auto result = MatchDeviceWithDriverIndex(dev, config);
  if (!result.is_ok()) {
    return result.error_value();
  }

  auto matched_drivers = std::move(result.value());
  for (auto driver : matched_drivers) {
    zx_status_t status = BindDriverToDevice(driver, dev);

    // If we get this here it means we've successfully bound one driver
    // and the device isn't multi-bind.
    if (status == ZX_ERR_ALREADY_BOUND) {
      return ZX_OK;
    }
  }

  return ZX_OK;
}

void BindDriverManager::BindAllDevicesDriverIndex(const DriverLoader::MatchDeviceConfig& config) {
  // This call is not strictly necessary -- we do not bind anything to the root device.
  // However, it guarantees that we connect to the driver index and wait for it to start.
  // Some tests become flaky if we don't do this here.
  zx_status_t status = MatchAndBindWithDriverIndex(coordinator_->root_device(), config);
  if (status != ZX_OK && status != ZX_ERR_NEXT) {
    LOGF(ERROR, "DriverIndex failed to match root_device: %d", status);
    return;
  }

  for (auto& dev : coordinator_->device_manager()->devices()) {
    auto dev_ref = fbl::RefPtr(&dev);
    zx_status_t status = MatchAndBindWithDriverIndex(dev_ref, config);
    if (status == ZX_ERR_NEXT || status == ZX_ERR_ALREADY_BOUND) {
      continue;
    }
    if (status != ZX_OK) {
      return;
    }
  }
}

zx_status_t BindDriverManager::AddDeviceGroup(
    std::string_view topological_path, std::string_view group_name,
    fuchsia_device_manager::wire::DeviceGroupDescriptor group_desc) {
  auto path = std::string(topological_path);
  if (device_groups_.count(path) != 0) {
    LOGF(ERROR, "Duplicate device groups already exists: %s", path.c_str());
    return ZX_ERR_INVALID_ARGS;
  }

  auto result = CompositeDevice::CreateForDeviceGroup(group_name, std::move(group_desc));
  if (!result.is_ok()) {
    LOGF(ERROR, "Failed to create CompositeDevice for device group: %s",
         zx_status_get_string(result.error_value()));
    return result.error_value();
  }

  device_groups_[path] = std::move(result.value());

  for (auto& dev : coordinator_->device_manager()->devices()) {
    MatchAndBindDeviceGroup(fbl::RefPtr(&dev), topological_path);
  }

  return ZX_OK;
}

zx_status_t BindDriverManager::MatchAndBindDeviceGroup(const fbl::RefPtr<Device>& dev,
                                                       std::string_view topological_path) {
  DriverLoader::MatchDeviceConfig config;
  auto result = MatchDeviceWithDriverIndex(dev, config);
  if (!result.is_ok()) {
    return result.error_value();
  }

  auto matched_drivers = std::move(result.value());
  for (auto driver : matched_drivers) {
    if (!std::holds_alternative<MatchedDeviceGroupInfo>(driver)) {
      continue;
    }

    auto device_group = std::get<MatchedDeviceGroupInfo>(driver);
    if (device_group.topological_path.compare(std::string(topological_path)) != 0) {
      continue;
    }

    zx_status_t status = BindDriverToDeviceGroup(device_group, dev);

    // If we get this here it means we've successfully bound one driver
    // and the device isn't multi-bind.
    if (status == ZX_ERR_ALREADY_BOUND) {
      return ZX_OK;
    }
  }

  return ZX_OK;
}

zx_status_t BindDriverManager::BindDriverToFragment(const MatchedCompositeDriverInfo& driver,
                                                    const fbl::RefPtr<Device>& dev) {
  // Check if the driver already exists in |driver_index_composite_devices_|. If
  // it doesn't, create and add a new CompositeDevice.
  std::string name(driver.driver_info.driver->libname.c_str());
  if (driver_index_composite_devices_.count(name) == 0) {
    std::unique_ptr<CompositeDevice> composite_dev;
    zx_status_t status = CompositeDevice::CreateFromDriverIndex(driver, &composite_dev);
    if (status != ZX_OK) {
      LOGF(ERROR, "Failed to create CompositeDevice from DriverIndex: %s",
           zx_status_get_string(status));
      return status;
    }
    driver_index_composite_devices_[name] = std::move(composite_dev);
  }

  // Bind the matched fragment to the device.
  auto& composite = driver_index_composite_devices_[name];
  zx_status_t status = composite->BindFragment(driver.composite.node, dev);
  if (status != ZX_OK) {
    LOGF(ERROR, "Failed to BindFragment for '%.*s': %s", static_cast<uint32_t>(dev->name().size()),
         dev->name().data(), zx_status_get_string(status));
  }
  return status;
}

zx_status_t BindDriverManager::BindDriverToDeviceGroup(const MatchedDeviceGroupInfo& device_group,
                                                       const fbl::RefPtr<Device>& dev) {
  auto path = std::string(device_group.topological_path);
  if (device_groups_.count(path) == 0) {
    return ZX_ERR_NOT_FOUND;
  }

  // Bind the matched fragment to the device.
  auto& composite = device_groups_[path];
  auto status = composite->BindFragment(device_group.node_index, dev);
  if (status != ZX_OK) {
    LOGF(ERROR, "Failed to BindFragment for '%.*s': %s", static_cast<uint32_t>(dev->name().size()),
         dev->name().data(), zx_status_get_string(status));
  }

  return status;
}
