[input_sample] Update to DriverBase

Updates the input sample driver to the DriverBase library. Starts using
the driver::Connect to connect to parent compat service and removes the
custom function for it. General build dependency cleanup.

Bug: 110283, 110915
Tests: Ran the driver and confirmed seeing input report from tool

Change-Id: Iccd712fb84ae8ee443251fd1309c1d37b394031e
Reviewed-on: https://fuchsia-review.googlesource.com/c/sdk-samples/drivers/+/737669
Reviewed-by: David Gilhooley <dgilhooley@google.com>
Commit-Queue: Novin Changizi <novinc@google.com>
Reviewed-by: Renato Mangini Dias <mangini@google.com>
Reviewed-by: Suraj Malhotra <surajmalhotra@google.com>
Reviewed-by: Dave Smith <smithdave@google.com>
diff --git a/src/input_sample/BUILD.bazel b/src/input_sample/BUILD.bazel
index c6778ae..b71909d 100644
--- a/src/input_sample/BUILD.bazel
+++ b/src/input_sample/BUILD.bazel
@@ -14,7 +14,7 @@
     name = "bind_bytecode",
     output = "input_sample.bindbc",
     rules = "input_sample.bind",
-    deps = [ "@fuchsia_sdk//bind/fuchsia.acpi" ],
+    deps = ["@fuchsia_sdk//bind/fuchsia.acpi"],
 )
 
 cc_binary(
@@ -23,20 +23,17 @@
         "driver_compat.h",
         "input_sample.cc",
         "input_sample.h",
+        "input_server.cc",
+        "input_server.h",
     ],
     linkshared = True,
     deps = [
         "@fuchsia_sdk//fidl/fuchsia.device.fs:fuchsia.device.fs_llcpp_cc",
         "@fuchsia_sdk//fidl/fuchsia.driver.compat:fuchsia.driver.compat_llcpp_cc",
         "@fuchsia_sdk//fidl/fuchsia.input.report:fuchsia.input.report_llcpp_cc",
-        "@fuchsia_sdk//fidl/zx:zx_cc",
         "@fuchsia_sdk//pkg/async-cpp",
         "@fuchsia_sdk//pkg/driver2_cpp",
-        "@fuchsia_sdk//pkg/driver_runtime_cpp",
-        "@fuchsia_sdk//pkg/fidl_cpp_wire",
         "@fuchsia_sdk//pkg/input_report_reader",
-        "@fuchsia_sdk//pkg/sys_component_cpp",
-        "@fuchsia_sdk//pkg/zx",
     ],
 )
 
diff --git a/src/input_sample/driver_compat.h b/src/input_sample/driver_compat.h
index a52e20c..c7fc2ce 100644
--- a/src/input_sample/driver_compat.h
+++ b/src/input_sample/driver_compat.h
@@ -10,16 +10,6 @@
 
 namespace input_driver_compat {
 
-// Connect to parent device node using fuchsia.driver.compat.Service
-zx::status<fidl::ClientEnd<fuchsia_driver_compat::Device>> ConnectToParentDevice(
-    const driver::Namespace* ns, std::string_view name) {
-  auto result = ns->OpenService<fuchsia_driver_compat::Service>(name);
-  if (result.is_error()) {
-    return result.take_error();
-  }
-  return result.value().connect_device();
-}
-
 // Connect to the fuchsia.devices.fs.Exporter protocol
 zx::status<fidl::ClientEnd<fuchsia_device_fs::Exporter>> ConnectToDeviceExporter(
     const driver::Namespace* ns) {
diff --git a/src/input_sample/input_sample.cc b/src/input_sample/input_sample.cc
index d224f2b..c94a36d 100644
--- a/src/input_sample/input_sample.cc
+++ b/src/input_sample/input_sample.cc
@@ -5,168 +5,33 @@
 #include "input_sample.h"
 
 #include <lib/async/cpp/task.h>
+#include <lib/driver2/service_client.h>
 
 #include "driver_compat.h"
 
-namespace {
-
-constexpr uint8_t kMouseButtonCount = 3;
-
-// FIDL server implementation for the `fuchsia.input.report/InputDevice` protocol
-class InputSampleServer : public fidl::WireServer<fuchsia_input_report::InputDevice> {
- public:
-  explicit InputSampleServer(
-      driver::Namespace& ns, async_dispatcher_t* dispatcher,
-      std::weak_ptr<input_report_reader::InputReportReaderManager<input_sample::SampleInputReport>>
-          input_report_readers)
-      : dispatcher_(dispatcher), input_report_readers_(input_report_readers) {
-    auto logger_result = driver::Logger::Create(ns, dispatcher, "input-sample-server");
-    ZX_ASSERT(logger_result.is_ok());
-    logger_ = std::move(*logger_result);
-  }
-
-  // Handle incoming connection requests from FIDL clients
-  static fidl::ServerBindingRef<fuchsia_input_report::InputDevice> BindDeviceClient(
-      driver::Namespace& ns, async_dispatcher_t* dispatcher,
-      std::weak_ptr<input_report_reader::InputReportReaderManager<input_sample::SampleInputReport>>
-          input_report_readers,
-      fidl::ServerEnd<fuchsia_input_report::InputDevice> request) {
-    // Bind each connection request to a unique FIDL server instance
-    auto server_impl = std::make_unique<InputSampleServer>(ns, dispatcher, input_report_readers);
-    return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl),
-                            std::mem_fn(&InputSampleServer::OnUnbound));
-  }
-
-  // This method is called when a server connection is torn down.
-  void OnUnbound(fidl::UnbindInfo info,
-                 fidl::ServerEnd<fuchsia_input_report::InputDevice> server_end) {
-    if (info.is_peer_closed()) {
-      FDF_LOG(DEBUG, "Client disconnected");
-    } else if (!info.is_user_initiated()) {
-      FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string());
-    }
-  }
-
-  void GetInputReportsReader(GetInputReportsReaderRequestView request,
-                             GetInputReportsReaderCompleter::Sync& completer) override;
-  void GetDescriptor(GetDescriptorCompleter::Sync& completer) override;
-
-  void SendOutputReport(SendOutputReportRequestView request,
-                        SendOutputReportCompleter::Sync& completer) override {
-    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-  }
-  void GetFeatureReport(GetFeatureReportCompleter::Sync& completer) override {
-    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-  }
-  void SetFeatureReport(SetFeatureReportRequestView request,
-                        SetFeatureReportCompleter::Sync& completer) override {
-    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-  }
-  void GetInputReport(GetInputReportRequestView request,
-                      GetInputReportCompleter::Sync& completer) override {
-    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-  }
-
- private:
-  driver::Logger logger_;
-  async_dispatcher_t* const dispatcher_;
-  std::weak_ptr<input_report_reader::InputReportReaderManager<input_sample::SampleInputReport>>
-      input_report_readers_;
-};
-
-// Protocol method for `fuchsia.input.report/InputDevice` to begin serving input reports
-void InputSampleServer::GetInputReportsReader(GetInputReportsReaderRequestView request,
-                                              GetInputReportsReaderCompleter::Sync& completer) {
-  auto reader_manager = input_report_readers_.lock();
-  if (!reader_manager) {
-    FDF_LOG(ERROR, "Unable to access InputReport reader manager.");
-    request->reader.Close(ZX_ERR_BAD_STATE);
-    return;
-  }
-
-  zx_status_t status = reader_manager->CreateReader(dispatcher_, std::move(request->reader));
-  if (status != ZX_OK) {
-    FDF_LOG(ERROR, "Could not create input report reader: %d", status);
-    request->reader.Close(ZX_ERR_BAD_STATE);
-  }
-}
-
-// Protocol method for `fuchsia.input.report/InputDevice` to return the device descriptor
-void InputSampleServer::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
-  fidl::Arena allocator;
-  auto descriptor = fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator);
-
-  fuchsia_input_report::wire::DeviceInfo device_info;
-  // We pick random VID/PIDs here, but these should be taken from the HID device,
-  // or defined in fuchsia.input.report/device_ids.fidl
-  device_info.vendor_id = 0x12345678;
-  device_info.product_id = 0x87654321;
-
-  fidl::VectorView<uint8_t> buttons(allocator, kMouseButtonCount);
-  buttons[0] = 0x01;
-  buttons[1] = 0x02;
-  buttons[2] = 0x03;
-
-  constexpr fuchsia_input_report::wire::Axis movement_x{
-      .range = {.min = -127, .max = 127},
-      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
-  };
-  constexpr fuchsia_input_report::wire::Axis movement_y{
-      .range = {.min = -127, .max = 127},
-      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
-  };
-
-  auto mouse_in_desc = fuchsia_input_report::wire::MouseInputDescriptor::Builder(allocator);
-  mouse_in_desc.buttons(buttons);
-  mouse_in_desc.movement_x(movement_x);
-  mouse_in_desc.movement_y(movement_y);
-
-  auto mouse_descriptor = fuchsia_input_report::wire::MouseDescriptor::Builder(allocator);
-  mouse_descriptor.input(mouse_in_desc.Build());
-  descriptor.mouse(mouse_descriptor.Build());
-  descriptor.device_info(device_info);
-
-  completer.Reply(descriptor.Build());
-}
-
-}  // namespace
-
 namespace input_sample {
 
-// static
-zx::status<std::unique_ptr<InputSampleDriver>> InputSampleDriver::Start(
-    fuchsia_driver_framework::wire::DriverStartArgs& start_args, fdf::UnownedDispatcher dispatcher,
-    fidl::WireSharedClient<fuchsia_driver_framework::Node> node, driver::Namespace ns,
-    driver::Logger logger) {
-  auto driver = std::make_unique<InputSampleDriver>(dispatcher->async_dispatcher(), std::move(node),
-                                                    std::move(ns), std::move(logger));
-  auto result = driver->Run(std::move(start_args.outgoing_dir()));
-  if (result.is_error()) {
-    return result.take_error();
-  }
-  return zx::ok(std::move(driver));
-}
-
-zx::status<> InputSampleDriver::Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir) {
+zx::status<> InputSampleDriver::Start() {
   // Connect to the parent device node.
-  auto parent = input_driver_compat::ConnectToParentDevice(&ns_, "default");
+  auto parent =
+      driver::Connect<fuchsia_driver_compat::Service::Device>(*context().incoming(), "default");
   if (parent.status_value() != ZX_OK) {
     FDF_SLOG(ERROR, "Failed to connect to parent", KV("status", parent.status_string()));
     return parent.take_error();
   }
 
   // Add the fuchsia.input.report/InputDevice protocol to be served as "/svc/input-sample"
-  auto result = outgoing_.AddProtocol<fuchsia_input_report::InputDevice>(
+  auto result = context().outgoing()->component().AddProtocol<fuchsia_input_report::InputDevice>(
       [this](fidl::ServerEnd<fuchsia_input_report::InputDevice> request) {
-        InputSampleServer::BindDeviceClient(ns_, dispatcher_, input_report_readers_,
+        InputSampleServer::BindDeviceClient(logger_, async_dispatcher(), input_report_readers_,
                                             std::move(request));
       },
-      Name());
+      kName);
   if (result.status_value() != ZX_OK) {
     return result;
   }
 
-  auto service_dir = fidl::StringView::FromExternal(std::string("svc/").append(Name()));
+  auto service_dir = fidl::StringView::FromExternal(std::string("svc/").append(kName));
 
   // Construct a devfs path that matches the device nodes topological path
   auto path_result = fidl::WireCall(*parent)->GetTopologicalPath();
@@ -175,27 +40,22 @@
     return zx::error(path_result.status());
   }
   std::string parent_path(path_result->path.data(), path_result->path.size());
-  auto devfs_path = fidl::StringView::FromExternal(parent_path.append("/").append(Name()));
+  auto devfs_path = fidl::StringView::FromExternal(parent_path.append("/").append(kName));
 
   // Export an entry to devfs for fuchsia.input.report as an input device class
-  auto devfs_dir =
-      input_driver_compat::ExportDevfsEntry(&ns_, service_dir, devfs_path, /* INPUT_REPORT */ 26);
+  auto devfs_dir = input_driver_compat::ExportDevfsEntry(context().incoming().get(), service_dir,
+                                                         devfs_path, /* INPUT_REPORT */ 26);
   if (devfs_dir.is_error()) {
     FDF_SLOG(ERROR, "Failed to export service", KV("status", devfs_dir.status_string()));
     return devfs_dir.take_error();
   }
 
   // Serve the driver's FIDL protocol to clients.
-  auto status = outgoing_.Serve(std::move(devfs_dir.value()));
+  auto status = context().outgoing()->Serve(std::move(devfs_dir.value()));
   if (status.is_error()) {
     FDF_SLOG(ERROR, "Failed to serve devfs directory", KV("status", status.status_string()));
     return status.take_error();
   }
-  status = outgoing_.Serve(std::move(outgoing_dir));
-  if (status.is_error()) {
-    FDF_SLOG(ERROR, "Failed to serve outgoing directory", KV("status", status.status_string()));
-    return status.take_error();
-  }
 
   // Start sending fake reports
   input_report_readers_ =
@@ -205,31 +65,6 @@
   return zx::ok();
 }
 
-// Convert local data structure to a `fuchsia.input.report/InputReport` format.
-void SampleInputReport::ToFidlInputReport(
-    fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
-    fidl::AnyArena& arena) {
-  std::vector<uint8_t> pressed_buttons;
-  for (uint8_t i = 0; i < kMouseButtonCount; i++) {
-    if (buttons & (1 << i)) {
-      pressed_buttons.push_back(i + 1);
-    }
-  }
-  fidl::VectorView<uint8_t> buttons_vec(arena, pressed_buttons.size());
-  size_t idx = 0;
-  for (const auto& button : pressed_buttons) {
-    buttons_vec[idx++] = button;
-  }
-
-  auto mouse_input_rpt = fuchsia_input_report::wire::MouseInputReport::Builder(arena);
-  mouse_input_rpt.pressed_buttons(buttons_vec);
-  mouse_input_rpt.movement_x(rel_x);
-  mouse_input_rpt.movement_y(rel_y);
-
-  input_report.mouse(mouse_input_rpt.Build());
-  input_report.event_time(event_time.get());
-}
-
 // Periodically send a new input report with fake data.
 void InputSampleDriver::SendFakeReport() {
   // Update fake mouse report
@@ -243,9 +78,9 @@
 
   // Run again in 1 second
   async::PostDelayedTask(
-      dispatcher_, [this]() mutable { SendFakeReport(); }, zx::sec(1));
+      async_dispatcher(), [this]() mutable { SendFakeReport(); }, zx::sec(1));
 }
 
 }  // namespace input_sample
 
-FUCHSIA_DRIVER_RECORD_CPP_V1(input_sample::InputSampleDriver);
+FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<input_sample::InputSampleDriver>);
diff --git a/src/input_sample/input_sample.h b/src/input_sample/input_sample.h
index 05be5b1..41a6ab9 100644
--- a/src/input_sample/input_sample.h
+++ b/src/input_sample/input_sample.h
@@ -5,67 +5,26 @@
 #ifndef FUCHSIA_SDK_EXAMPLES_CC_INPUT_SAMPLE_H_
 #define FUCHSIA_SDK_EXAMPLES_CC_INPUT_SAMPLE_H_
 
-#include <fidl/fuchsia.device.fs/cpp/wire.h>
-#include <fidl/fuchsia.driver.framework/cpp/wire.h>
-#include <fidl/fuchsia.input.report/cpp/wire.h>
-#include <lib/async/dispatcher.h>
-#include <lib/driver2/namespace.h>
-#include <lib/driver2/record_cpp.h>
-#include <lib/driver2/structured_logger.h>
-#include <lib/fdf/cpp/dispatcher.h>
-#include <lib/input_report_reader/reader.h>
-#include <lib/sys/component/cpp/outgoing_directory.h>
-#include <lib/zx/status.h>
-#include <unistd.h>
+#include <lib/driver2/driver2_cpp.h>
 
-#include <memory>
-#include <mutex>
+#include "input_server.h"
 
 namespace input_sample {
 
-// Used by the input report reader library to transform reports over FIDL
-struct SampleInputReport {
-  zx::time event_time;
-  uint8_t buttons = 0;
-  int8_t rel_x = 0;
-  int8_t rel_y = 0;
-
-  void ToFidlInputReport(
-      fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
-      fidl::AnyArena& arena);
-};
-
 // Sample driver for a virtual input device that generates input reports.
-class InputSampleDriver {
+class InputSampleDriver : public driver::DriverBase {
+  static constexpr std::string_view kName = "input-sample";
+
  public:
-  InputSampleDriver(async_dispatcher_t* dispatcher,
-                    fidl::WireSharedClient<fuchsia_driver_framework::Node> node,
-                    driver::Namespace ns, driver::Logger logger)
-      : dispatcher_(dispatcher),
-        outgoing_(component::OutgoingDirectory::Create(dispatcher)),
-        node_(std::move(node)),
-        ns_(std::move(ns)),
-        logger_(std::move(logger)) {}
+  InputSampleDriver(driver::DriverStartArgs start_args, fdf::UnownedDispatcher driver_dispatcher)
+      : driver::DriverBase(kName, std::move(start_args), std::move(driver_dispatcher)) {}
   virtual ~InputSampleDriver() = default;
 
-  static constexpr const char* Name() { return "input-sample"; }
-
-  static zx::status<std::unique_ptr<InputSampleDriver>> Start(
-      fuchsia_driver_framework::wire::DriverStartArgs& start_args,
-      fdf::UnownedDispatcher dispatcher,
-      fidl::WireSharedClient<fuchsia_driver_framework::Node> node, driver::Namespace ns,
-      driver::Logger logger);
+  zx::status<> Start() override;
 
  private:
-  zx::status<> Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir);
   void SendFakeReport();
 
-  async_dispatcher_t* const dispatcher_;
-  component::OutgoingDirectory outgoing_;
-  fidl::WireSharedClient<fuchsia_driver_framework::Node> node_;
-  driver::Namespace ns_;
-  driver::Logger logger_;
-
   std::shared_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>>
       input_report_readers_;
   SampleInputReport report_;
diff --git a/src/input_sample/input_server.cc b/src/input_sample/input_server.cc
new file mode 100644
index 0000000..81b4c30
--- /dev/null
+++ b/src/input_sample/input_server.cc
@@ -0,0 +1,112 @@
+// 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 "input_server.h"
+
+namespace input_sample {
+
+// Convert local data structure to a `fuchsia.input.report/InputReport` format.
+void SampleInputReport::ToFidlInputReport(
+    fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
+    fidl::AnyArena& arena) {
+  std::vector<uint8_t> pressed_buttons;
+  for (uint8_t i = 0; i < kMouseButtonCount; i++) {
+    if (buttons & (1 << i)) {
+      pressed_buttons.push_back(i + 1);
+    }
+  }
+  fidl::VectorView<uint8_t> buttons_vec(arena, pressed_buttons.size());
+  size_t idx = 0;
+  for (const auto& button : pressed_buttons) {
+    buttons_vec[idx++] = button;
+  }
+
+  auto mouse_input_rpt = fuchsia_input_report::wire::MouseInputReport::Builder(arena);
+  mouse_input_rpt.pressed_buttons(buttons_vec);
+  mouse_input_rpt.movement_x(rel_x);
+  mouse_input_rpt.movement_y(rel_y);
+
+  input_report.mouse(mouse_input_rpt.Build());
+  input_report.event_time(event_time.get());
+}
+
+// Static
+// Handle incoming connection requests from FIDL clients
+fidl::ServerBindingRef<fuchsia_input_report::InputDevice> InputSampleServer::BindDeviceClient(
+    driver::Logger& logger, async_dispatcher_t* dispatcher,
+    std::weak_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>>
+        input_report_readers,
+    fidl::ServerEnd<fuchsia_input_report::InputDevice> request) {
+  // Bind each connection request to a unique FIDL server instance
+  auto server_impl = std::make_unique<InputSampleServer>(logger, dispatcher, input_report_readers);
+  return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl),
+                          std::mem_fn(&InputSampleServer::OnUnbound));
+}
+
+// This method is called when a server connection is torn down.
+void InputSampleServer::OnUnbound(fidl::UnbindInfo info,
+                                  fidl::ServerEnd<fuchsia_input_report::InputDevice> server_end) {
+  if (info.is_peer_closed()) {
+    FDF_LOG(DEBUG, "Client disconnected");
+  } else if (!info.is_user_initiated()) {
+    FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string());
+  }
+}
+
+// Protocol method for `fuchsia.input.report/InputDevice` to begin serving input reports
+void InputSampleServer::GetInputReportsReader(GetInputReportsReaderRequestView request,
+                                              GetInputReportsReaderCompleter::Sync& completer) {
+  auto reader_manager = input_report_readers_.lock();
+  if (!reader_manager) {
+    FDF_LOG(ERROR, "Unable to access InputReport reader manager.");
+    request->reader.Close(ZX_ERR_BAD_STATE);
+    return;
+  }
+
+  zx_status_t status = reader_manager->CreateReader(dispatcher_, std::move(request->reader));
+  if (status != ZX_OK) {
+    FDF_LOG(ERROR, "Could not create input report reader: %d", status);
+    request->reader.Close(ZX_ERR_BAD_STATE);
+  }
+}
+
+// Protocol method for `fuchsia.input.report/InputDevice` to return the device descriptor
+void InputSampleServer::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
+  fidl::Arena allocator;
+  auto descriptor = fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator);
+
+  fuchsia_input_report::wire::DeviceInfo device_info;
+  // We pick random VID/PIDs here, but these should be taken from the HID device,
+  // or defined in fuchsia.input.report/device_ids.fidl
+  device_info.vendor_id = 0x12345678;
+  device_info.product_id = 0x87654321;
+
+  fidl::VectorView<uint8_t> buttons(allocator, kMouseButtonCount);
+  buttons[0] = 0x01;
+  buttons[1] = 0x02;
+  buttons[2] = 0x03;
+
+  constexpr fuchsia_input_report::wire::Axis movement_x{
+      .range = {.min = -127, .max = 127},
+      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
+  };
+  constexpr fuchsia_input_report::wire::Axis movement_y{
+      .range = {.min = -127, .max = 127},
+      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
+  };
+
+  auto mouse_in_desc = fuchsia_input_report::wire::MouseInputDescriptor::Builder(allocator);
+  mouse_in_desc.buttons(buttons);
+  mouse_in_desc.movement_x(movement_x);
+  mouse_in_desc.movement_y(movement_y);
+
+  auto mouse_descriptor = fuchsia_input_report::wire::MouseDescriptor::Builder(allocator);
+  mouse_descriptor.input(mouse_in_desc.Build());
+  descriptor.mouse(mouse_descriptor.Build());
+  descriptor.device_info(device_info);
+
+  completer.Reply(descriptor.Build());
+}
+
+}  // namespace input_sample
diff --git a/src/input_sample/input_server.h b/src/input_sample/input_server.h
new file mode 100644
index 0000000..de8e3b8
--- /dev/null
+++ b/src/input_sample/input_server.h
@@ -0,0 +1,77 @@
+// 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.
+
+#ifndef FUCHSIA_SDK_EXAMPLES_CC_INPUT_SAMPLE_INPUT_SERVER_H_
+#define FUCHSIA_SDK_EXAMPLES_CC_INPUT_SAMPLE_INPUT_SERVER_H_
+
+#include <fidl/fuchsia.input.report/cpp/wire.h>
+#include <lib/driver2/logger.h>
+#include <lib/input_report_reader/reader.h>
+
+namespace input_sample {
+
+constexpr uint8_t kMouseButtonCount = 3;
+
+// Used by the input report reader library to transform reports over FIDL
+struct SampleInputReport {
+  zx::time event_time;
+  uint8_t buttons = 0;
+  int8_t rel_x = 0;
+  int8_t rel_y = 0;
+
+  void ToFidlInputReport(
+      fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
+      fidl::AnyArena& arena);
+};
+
+// FIDL server implementation for the `fuchsia.input.report/InputDevice` protocol
+class InputSampleServer : public fidl::WireServer<fuchsia_input_report::InputDevice> {
+ public:
+  InputSampleServer(driver::Logger& logger, async_dispatcher_t* dispatcher,
+                    std::weak_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>>
+                        input_report_readers)
+      : logger_(logger), dispatcher_(dispatcher), input_report_readers_(input_report_readers) {}
+
+  static fidl::ServerBindingRef<fuchsia_input_report::InputDevice> BindDeviceClient(
+      driver::Logger& logger, async_dispatcher_t* dispatcher,
+      std::weak_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>>
+          input_report_readers,
+      fidl::ServerEnd<fuchsia_input_report::InputDevice> request);
+
+  void OnUnbound(fidl::UnbindInfo info,
+                 fidl::ServerEnd<fuchsia_input_report::InputDevice> server_end);
+
+  // fidl::WireServer<fuchsia_input_report::InputDevice>
+
+  void GetInputReportsReader(GetInputReportsReaderRequestView request,
+                             GetInputReportsReaderCompleter::Sync& completer) override;
+
+  void GetDescriptor(GetDescriptorCompleter::Sync& completer) override;
+
+  void SendOutputReport(SendOutputReportRequestView request,
+                        SendOutputReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+  void GetFeatureReport(GetFeatureReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+  void SetFeatureReport(SetFeatureReportRequestView request,
+                        SetFeatureReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+  void GetInputReport(GetInputReportRequestView request,
+                      GetInputReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+
+ private:
+  driver::Logger& logger_;
+  async_dispatcher_t* const dispatcher_;
+  std::weak_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>>
+      input_report_readers_;
+};
+
+}  // namespace input_sample
+
+#endif  // FUCHSIA_SDK_EXAMPLES_CC_INPUT_SAMPLE_INPUT_SERVER_H_