// Copyright 2017 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 "input.h"

#include <lib/ddk/debug.h>
#include <lib/fit/defer.h>
#include <limits.h>
#include <string.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/status.h>

#include <algorithm>
#include <memory>
#include <utility>

#include <fbl/algorithm.h>
#include <fbl/auto_lock.h>

#include "src/devices/bus/lib/virtio/trace.h"
#include "src/ui/input/drivers/virtio/cpp/input_kbd.h"
#include "src/ui/input/drivers/virtio/cpp/input_mouse.h"
#include "src/ui/input/drivers/virtio/cpp/input_touch.h"

#define LOCAL_TRACE 0

namespace virtio {

InputDevice::InputDevice(zx_device_t* bus_device, zx::bti bti, std::unique_ptr<Backend> backend)
    : virtio::Device(std::move(bti), std::move(backend)),
      ddk::Device<InputDevice, ddk::Messageable<fuchsia_input_report::InputDevice>::Mixin>(
          bus_device) {
  metrics_root_ = inspector_.GetRoot().CreateChild("hid-input-report-touch");
  total_report_count_ = metrics_root_.CreateUint("total_report_count", 0);
  last_event_timestamp_ = metrics_root_.CreateUint("last_event_timestamp", 0);
}

InputDevice::~InputDevice() {}

zx_status_t InputDevice::Init() {
  LTRACEF("Device %p\n", this);

  fbl::AutoLock lock(&lock_);

  // Reset the device and read configuration
  DeviceReset();

  SelectConfig(VIRTIO_INPUT_CFG_ID_NAME, 0);
  LTRACEF_LEVEL(2, "name %s\n", config_.u.string);

  SelectConfig(VIRTIO_INPUT_CFG_ID_SERIAL, 0);
  LTRACEF_LEVEL(2, "serial %s\n", config_.u.string);

  SelectConfig(VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
  if (config_.size >= sizeof(virtio_input_devids_t)) {
    LTRACEF_LEVEL(2, "bustype %d\n", config_.u.ids.bustype);
    LTRACEF_LEVEL(2, "vendor %d\n", config_.u.ids.vendor);
    LTRACEF_LEVEL(2, "product %d\n", config_.u.ids.product);
    LTRACEF_LEVEL(2, "version %d\n", config_.u.ids.version);
  }

  SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_KEY);
  uint8_t cfg_key_size = config_.size;
  SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_REL);
  uint8_t cfg_rel_size = config_.size;
  SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_ABS);
  uint8_t cfg_abs_size = config_.size;

  SelectConfig(VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_EV_MT_POSITION_X);
  virtio_input_absinfo_t x_info = config_.u.abs;
  SelectConfig(VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_EV_MT_POSITION_Y);
  virtio_input_absinfo_t y_info = config_.u.abs;

  // At the moment we support mice, keyboards, and touchscreens.
  // Support for more devices should be added here.
  SelectConfig(VIRTIO_INPUT_CFG_ID_NAME, 0);
  std::string device_name(config_.u.string, strnlen(config_.u.string, sizeof(config_.u.string)));
  SelectConfig(VIRTIO_INPUT_CFG_ID_SERIAL, 0);
  std::string device_serial(config_.u.string, strnlen(config_.u.string, sizeof(config_.u.string)));

  if ((x_info.max > 0) && (y_info.max > 0)) {
    // Touchscreen
    zxlogf(INFO, "Detected a touchscreen device: %s", device_name.c_str());
    hid_device_ = std::make_unique<HidTouch>(x_info, y_info, device_name, device_serial);
  } else if (cfg_rel_size > 0 || cfg_abs_size > 0) {
    // Mouse
    zxlogf(INFO, "Detected a mouse device: %s", device_name.c_str());
    hid_device_ = std::make_unique<HidMouse>(device_name, device_serial);
  } else if (cfg_key_size > 0) {
    // Keyboard
    zxlogf(INFO, "Detected a keyboard device: %s", device_name.c_str());
    hid_device_ = std::make_unique<HidKeyboard>(device_name, device_serial);
  } else {
    zxlogf(WARNING, "Detected an unsupported device: %s", device_name.c_str());
    return ZX_ERR_NOT_SUPPORTED;
  }

  DriverStatusAck();

  if (!(DeviceFeaturesSupported() & VIRTIO_F_VERSION_1)) {
    // Declaring non-support until there is a need in the future.
    zxlogf(ERROR, "Legacy virtio interface is not supported by this driver");
    return ZX_ERR_NOT_SUPPORTED;
  }
  DriverFeaturesAck(VIRTIO_F_VERSION_1);
  if (zx_status_t status = DeviceStatusFeaturesOk(); status != ZX_OK) {
    zxlogf(ERROR, "Feature negotiation failed: %s", zx_status_get_string(status));
    return status;
  }

  // Plan to clean up unless everything succeeds.
  auto cleanup = fit::defer([this]() { Release(); });

  // Allocate the main eventq vring
  zx_status_t status = eventq_vring_.Init(0, kEventCount);
  if (status != ZX_OK) {
    zxlogf(ERROR, "Failed to allocate eventq vring: %s", zx_status_get_string(status));
    return status;
  }

  // Allocate eventq buffers for the ring.
  // TODO: Avoid multiple allocations, allocate enough for all buffers once.
  for (uint16_t id = 0; id < kEventCount; ++id) {
    assert(sizeof(virtio_input_event_t) <= zx_system_get_page_size());
    status = io_buffer_init(&eventq_buffers_[id], bti_.get(), sizeof(virtio_input_event_t),
                            IO_BUFFER_RO | IO_BUFFER_CONTIG);
    if (status != ZX_OK) {
      zxlogf(ERROR, "Failed to allocate eventq I/O buffers: %s", zx_status_get_string(status));
      return status;
    }
  }

  // Expose eventq buffers to the host
  vring_desc* desc = nullptr;
  uint16_t id;
  for (uint16_t i = 0; i < kEventCount; ++i) {
    desc = eventq_vring_.AllocDescChain(1, &id);
    if (desc == nullptr) {
      zxlogf(ERROR, "Failed to allocate eventq descriptor chain");
      return ZX_ERR_NO_RESOURCES;
    }
    ZX_ASSERT(id < kEventCount);
    desc->addr = io_buffer_phys(&eventq_buffers_[id]);
    desc->len = sizeof(virtio_input_event_t);
    desc->flags |= VRING_DESC_F_WRITE;
    LTRACE_DO(virtio_dump_desc(desc));
    eventq_vring_.SubmitChain(id);
  }

  // Allocate the statusq vring
  status = statusq_vring_.Init(1, kStatusCount);
  if (status != ZX_OK) {
    zxlogf(ERROR, "Failed to allocate statusq vring: %s", zx_status_get_string(status));
    return status;
  }

  // Allocate statusq buffers for the ring.
  for (uint16_t id = 0; id < kStatusCount; ++id) {
    assert(sizeof(virtio_input_event_t) <= zx_system_get_page_size());
    status = io_buffer_init(&statusq_buffers_[id], bti_.get(), sizeof(virtio_input_event_t),
                            IO_BUFFER_RW | IO_BUFFER_CONTIG);
    if (status != ZX_OK) {
      zxlogf(ERROR, "Failed to allocate statusq I/O buffers: %s", zx_status_get_string(status));
      return status;
    }
  }

  // Expose statusq buffers to the host
  for (uint16_t i = 0; i < kStatusCount; ++i) {
    desc = statusq_vring_.AllocDescChain(1, &id);
    if (desc == nullptr) {
      zxlogf(ERROR, "Failed to allocate statusq descriptor chain");
      return ZX_ERR_NO_RESOURCES;
    }
    ZX_ASSERT(id < kStatusCount);
    desc->addr = io_buffer_phys(&statusq_buffers_[id]);
    desc->len = sizeof(virtio_input_event_t);
    desc->flags |= VRING_DESC_F_WRITE;
    LTRACE_DO(virtio_dump_desc(desc));
    statusq_vring_.SubmitChain(id);
  }

  StartIrqThread();
  DriverStatusOk();

  zx::result<> add_service_result =
      DdkAddService<fuchsia_input_report::Service>(fuchsia_input_report::Service::InstanceHandler({
          .input_device = bindings_.CreateHandler(
              this, fdf::Dispatcher::GetCurrent()->async_dispatcher(), fidl::kIgnoreBindingClosure),
      }));
  if (add_service_result.is_error()) {
    zxlogf(ERROR, "%s: failed to add service: %s", tag(), add_service_result.status_string());
    return add_service_result.status_value();
  }

  status = DdkAdd(ddk::DeviceAddArgs("virtio-input").set_inspect_vmo(inspector_.DuplicateVmo()));
  if (status != ZX_OK) {
    zxlogf(ERROR, "%s: failed to add device: %s", tag(), zx_status_get_string(status));
    return status;
  }

  eventq_vring_.Kick();
  cleanup.cancel();
  return ZX_OK;
}

void InputDevice::DdkRelease() {
  fbl::AutoLock lock(&lock_);
  for (size_t i = 0; i < kEventCount; ++i) {
    if (io_buffer_is_valid(&eventq_buffers_[i])) {
      io_buffer_release(&eventq_buffers_[i]);
    }
  }
  for (size_t i = 0; i < kStatusCount; ++i) {
    if (io_buffer_is_valid(&statusq_buffers_[i])) {
      io_buffer_release(&statusq_buffers_[i]);
    }
  }
}

void InputDevice::ReceiveEvent(virtio_input_event_t* event) {
  hid_device_->ReceiveEvent(event);

  if (event->type == VIRTIO_INPUT_EV_SYN) {
    // TODO(https://fxbug.dev/42143542): Currently we assume all input events are SYN_REPORT.
    // We need to handle other event codes like SYN_DROPPED as well.
    fbl::AutoLock lock(&lock_);
    total_report_count_.Add(1);
    last_event_timestamp_.Set(hid_device_->SendReportToAllReaders().get());
  }
}

void InputDevice::IrqRingUpdate() {
  auto free_chain = [this](vring_used_elem* used_elem) {
    uint16_t id = static_cast<uint16_t>(used_elem->id & 0xffff);
    vring_desc* desc = eventq_vring_.DescFromIndex(id);
    ZX_ASSERT(id < kEventCount);
    ZX_ASSERT(desc->len == sizeof(virtio_input_event_t));

    auto evt = static_cast<virtio_input_event_t*>(io_buffer_virt(&eventq_buffers_[id]));
    ReceiveEvent(evt);

    ZX_ASSERT((desc->flags & VRING_DESC_F_NEXT) == 0);
    eventq_vring_.FreeDesc(id);
  };

  eventq_vring_.IrqRingUpdate(free_chain);

  vring_desc* desc = nullptr;
  uint16_t id;
  bool need_kick = false;
  while ((desc = eventq_vring_.AllocDescChain(1, &id))) {
    desc->len = sizeof(virtio_input_event_t);
    eventq_vring_.SubmitChain(id);
    need_kick = true;
  }

  if (need_kick) {
    eventq_vring_.Kick();
  }
}

void InputDevice::IrqConfigChange() { LTRACEF("IrqConfigChange\n"); }

void InputDevice::SelectConfig(uint8_t select, uint8_t subsel) {
  WriteDeviceConfig(offsetof(virtio_input_config_t, select), select);
  WriteDeviceConfig(offsetof(virtio_input_config_t, subsel), subsel);
  CopyDeviceConfig(&config_, sizeof(config_));
}

void InputDevice::GetInputReportsReaderV2(GetInputReportsReaderV2RequestView request,
                                          GetInputReportsReaderV2Completer::Sync& completer) {
  const uint16_t max_unacknowledged_reports =
      std::clamp<uint16_t>(request->max_unacknowledged_reports_limit, 1, kMaxReportsPerHalfSecond);
  if (request->max_unacknowledged_reports_limit != max_unacknowledged_reports) {
    zxlogf(WARNING, "GetInputReportsReaderV2: requested limit %u clamped to %u",
           request->max_unacknowledged_reports_limit, max_unacknowledged_reports);
  }
  zx_status_t status =
      hid_device_->GetInputReportsReaderV2(fdf::Dispatcher::GetCurrent()->async_dispatcher(),
                                           std::move(request->reader), max_unacknowledged_reports);
  if (status != ZX_OK) {
    completer.Close(status);
    return;
  }
  completer.Reply(max_unacknowledged_reports);
}

}  // namespace virtio
