[wip][qemu][edu] Introduce a QEMU Edu Driver

The QEMU Edu device is a device used for educational purposes. The
spec for the device can be found at the following url:

https://github.com/qemu/qemu/blob/master/docs/specs/edu.txt

This CL introduces the following:
 + A Driver for the QEMU Edu Device
   + Supports the Factorial and Liveness Check Functions
   + Reports Device Version Number via Inspect
   - Does not support IRQ or DMA as of yet
   - Does not have an accompanying test as of yet
 + A FIDL interface to interact with the device
 + An eductl command line utility to issue commands against
   the device.

Change-Id: I1e387a9e1157ba27540d0ce0e924e69f40742403
diff --git a/build/drivers/all_drivers_list.txt b/build/drivers/all_drivers_list.txt
index 1d2a6dd..2d6f556 100644
--- a/build/drivers/all_drivers_list.txt
+++ b/build/drivers/all_drivers_list.txt
@@ -143,6 +143,7 @@
 //src/devices/misc/drivers/compat:v1_test
 //src/devices/misc/drivers/cpu-trace:cpu-trace-driver
 //src/devices/misc/drivers/packaged:lib
+//src/devices/misc/drivers/qemu-edu:driver
 //src/devices/misc/drivers/test-parent:test-parent-sys_driver
 //src/devices/misc/drivers/test:test-driver
 //src/devices/misc/drivers/virtio-rng:virtio_rng-driver
diff --git a/src/devices/bind/fuchsia.pci/fuchsia.pci.bind b/src/devices/bind/fuchsia.pci/fuchsia.pci.bind
index 0ee924d..a58ce03 100644
--- a/src/devices/bind/fuchsia.pci/fuchsia.pci.bind
+++ b/src/devices/bind/fuchsia.pci/fuchsia.pci.bind
@@ -18,6 +18,7 @@
   BROADCOM = 0x14e4,
   ATHEROS = 0x168c,
   INTEL = 0x8086,
+  QEMU_TEST = 0x1234,
 };
 
 extend uint fuchsia.BIND_PCI_DID {
@@ -41,6 +42,7 @@
   RTL8111 = 0x8168,
   INTEL_SPT_SPI0 = 0x9d29,
   GOOGLE_GRAPHICS_ADAPTER = 0xa002,
+  QEMU_EDU = 0x11e8,
 };
 
 extend uint fuchsia.BIND_PCI_CLASS {
diff --git a/src/devices/misc/bin/BUILD.gn b/src/devices/misc/bin/BUILD.gn
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/devices/misc/bin/BUILD.gn
diff --git a/src/devices/misc/drivers/qemu-edu/BUILD.gn b/src/devices/misc/drivers/qemu-edu/BUILD.gn
new file mode 100644
index 0000000..ce361e1
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/BUILD.gn
@@ -0,0 +1,43 @@
+# 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.
+
+import("//build/bind/bind.gni")
+import("//build/components.gni")
+import("//build/drivers.gni")
+
+driver_bind_rules("qemu_edu_bind") {
+  rules = "qemu-edu.bind"
+  header_output = "qemu_edu_bind.h"
+  tests = "bind_tests.json"
+  deps = [ "//src/devices/bind/fuchsia.pci" ]
+}
+
+common_deps = [
+  ":qemu_edu_bind",
+  "//src/devices/lib/driver",
+  "//src/lib/ddktl",
+  "//zircon/system/ulib/inspect",
+]
+
+fuchsia_driver("driver") {
+  output_name = "qemu-edu"
+  deps = common_deps
+  sources = [ "qemu-edu.cc" ]
+}
+
+fuchsia_driver_component("driver_component") {
+  component_name = "qemu-edu"
+  deps = [ ":driver" ]
+  info = "driver-info.json"
+}
+
+fuchsia_driver_package("qemu-edu") {
+  package_name = "qemu-edu"
+  driver_components = [ ":driver_component" ]
+}
+
+group("tests") {
+  testonly = true
+  deps = [ ":qemu_edu_bind_test" ]
+}
diff --git a/src/devices/misc/drivers/qemu-edu/bind_tests.json b/src/devices/misc/drivers/qemu-edu/bind_tests.json
new file mode 100644
index 0000000..a4873ef
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/bind_tests.json
@@ -0,0 +1,43 @@
+[
+    {
+        "device": {
+            "fuchsia.BIND_PROTOCOL": "fuchsia.bluetooth.BIND_PROTOCOL.DEVICE"
+        },
+        "expected": "abort",
+        "name": "Protocol"
+    },
+    {
+        "device": {
+            "fuchsia.BIND_COMPOSITE": "1",
+            "fuchsia.BIND_PCI_DID": "fuchsia.pci.BIND_PCI_DID.QEMU_EDU",
+            "fuchsia.BIND_PCI_VID": "fuchsia.pci.BIND_PCI_VID.QEMU_TEST",
+            "fuchsia.BIND_PROTOCOL": "fuchsia.pci.BIND_PROTOCOL.DEVICE"
+        },
+        "expected": "match",
+        "name": "Qemu EDU"
+    },
+    {
+        "device": {
+            "fuchsia.BIND_PCI_DID": "fuchsia.pci.BIND_PCI_DID.QEMU_EDU",
+            "fuchsia.BIND_PCI_VID": "fuchsia.pci.BIND_PCI_VID.QEMU_TEST"
+        },
+        "expected": "abort",
+        "name": "Missing Protocol"
+    },
+    {
+        "device": {
+            "fuchsia.BIND_PCI_DID": "fuchsia.pci.BIND_PCI_DID.QEMU_EDU",
+            "fuchsia.BIND_PROTOCOL": "fuchsia.pci.BIND_PROTOCOL.DEVICE"
+        },
+        "expected": "abort",
+        "name": "Missing PCI VID"
+    },
+    {
+        "device": {
+            "fuchsia.BIND_PCI_VID": "fuchsia.pci.BIND_PCI_VID.QEMU_TEST",
+            "fuchsia.BIND_PROTOCOL": "fuchsia.pci.BIND_PROTOCOL.DEVICE"
+        },
+        "expected": "abort",
+        "name": "Missing PCI DID"
+    }
+]
diff --git a/src/devices/misc/drivers/qemu-edu/driver-info.json b/src/devices/misc/drivers/qemu-edu/driver-info.json
new file mode 100644
index 0000000..b40b202
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/driver-info.json
@@ -0,0 +1,9 @@
+{
+    "short_description": "QEMU Edu Device Driver",
+    "manufacturer": "QEMU",
+    "families": [],
+    "models": [],
+    "areas": [
+        "Misc"
+    ]
+}
diff --git a/src/devices/misc/drivers/qemu-edu/qemu-edu.bind b/src/devices/misc/drivers/qemu-edu/qemu-edu.bind
new file mode 100644
index 0000000..62bbfab
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/qemu-edu.bind
@@ -0,0 +1,10 @@
+// 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.
+
+using fuchsia.pci;
+
+fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
+fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.QEMU_TEST;
+fuchsia.BIND_PCI_DID == fuchsia.pci.BIND_PCI_DID.QEMU_EDU;
+//fuchsia.BIND_COMPOSITE == 1;
diff --git a/src/devices/misc/drivers/qemu-edu/qemu-edu.cc b/src/devices/misc/drivers/qemu-edu/qemu-edu.cc
new file mode 100644
index 0000000..77eea6d
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/qemu-edu.cc
@@ -0,0 +1,40 @@
+// 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 "qemu-edu.h"
+
+#include <lib/ddk/driver.h>
+
+#include "src/devices/misc/drivers/qemu-edu/qemu_edu_bind.h"
+
+namespace qemu_edu {
+
+zx_status_t QemuEduDevice::Create(void* ctx, zx_device_t* parent) {
+  auto dev = std::make_unique<QemuEduDevice>(parent);
+
+  zx_status_t status = dev->DdkAdd(ddk::DeviceAddArgs("qemu-edu")
+                                       .set_flags(DEVICE_ADD_NON_BINDABLE)
+                                       .set_inspect_vmo(dev->inspector_.DuplicateVmo()));
+
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "ddk add failed, st = %d", status);
+    return status;
+  }
+
+  __UNUSED auto ptr = dev.release();
+
+  return ZX_OK;
+}
+
+static zx_driver_ops_t driver_ops = []() {
+  zx_driver_ops_t ops = {};
+  ops.version = DRIVER_OPS_VERSION;
+  ops.bind = QemuEduDevice::Create;
+  return ops;
+}();
+
+}  // namespace qemu_edu
+
+// clang-format off
+ZIRCON_DRIVER(qemu-edu, qemu_edu::driver_ops, "zircon", "0.1");
diff --git a/src/devices/misc/drivers/qemu-edu/qemu-edu.h b/src/devices/misc/drivers/qemu-edu/qemu-edu.h
new file mode 100644
index 0000000..de25a2c
--- /dev/null
+++ b/src/devices/misc/drivers/qemu-edu/qemu-edu.h
@@ -0,0 +1,35 @@
+// 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 SRC_DEVICES_MISC_DRIVERS_QEMU_EDU_QEMU_EDU_H_
+#define SRC_DEVICES_MISC_DRIVERS_QEMU_EDU_QEMU_EDU_H_
+
+#include <lib/inspect/cpp/inspector.h>
+
+#include <ddktl/device.h>
+
+namespace qemu_edu {
+
+class QemuEduDevice;
+using DeviceType =
+    ddk::Device<QemuEduDevice>;
+
+class QemuEduDevice : public DeviceType {
+ public:
+  QemuEduDevice(zx_device_t* device) : DeviceType(device) {}
+
+  // Implement DDK Device Ops
+  static zx_status_t Create(void* ctx, zx_device_t* parent);
+  void DdkRelease() { delete this; }
+
+ protected:
+  inspect::Inspector inspector_;
+  inspect::Node edu_info_ = inspector_.GetRoot().CreateChild("qemu_edu_device");
+
+ private:
+  std::mutex lock_;
+};
+
+}  // namespace qemu_edu
+
+#endif  // SRC_DEVICES_MISC_DRIVERS_QEMU_EDU_QEMU_EDU_H_