[ddk] Add support to call compatibility tests

This change adds fidl support to run compatibility tests from isolated
devmgr. This change adds test drivers and runs the compatibility tests
on the test driver, and in-turn verifies the compatibility tests.

Test: runtests -t ddk-runcompatibilityhook-test

Change-Id: I9c6cc6d69ab9db3c0a5bed63493efe1d3b3eaf58
diff --git a/zircon/system/core/devmgr/devcoordinator/device.cpp b/zircon/system/core/devmgr/devcoordinator/device.cpp
index e53ed2f..0f9e906 100644
--- a/zircon/system/core/devmgr/devcoordinator/device.cpp
+++ b/zircon/system/core/devmgr/devcoordinator/device.cpp
@@ -291,6 +291,7 @@
 static zx_status_t fidl_MakeVisible(void* ctx, fidl_txn_t* txn);
 static zx_status_t fidl_BindDevice(void* ctx, const char* driver_path_data, size_t driver_path_size,
                                    fidl_txn_t* txn);
+static zx_status_t fidl_RunCompatibilityTests(void* ctx, fidl_txn_t* txn);
 static zx_status_t fidl_GetTopologicalPath(void* ctx, fidl_txn_t* txn);
 static zx_status_t fidl_LoadFirmware(void* ctx, const char* fw_path_data, size_t fw_path_size,
                                      fidl_txn_t* txn);
@@ -323,6 +324,7 @@
 
     .DmMexec = fidl_DmMexec,
     .DirectoryWatch = fidl_DirectoryWatch,
+    .RunCompatibilityTests = fidl_RunCompatibilityTests,
 };
 
 zx_status_t Device::HandleRead() {
@@ -578,6 +580,12 @@
     return fuchsia_device_manager_CoordinatorBindDevice_reply(txn, status);
 }
 
+static zx_status_t fidl_RunCompatibilityTests(void* ctx, fidl_txn_t* txn) {
+    auto dev = fbl::WrapRefPtr(static_cast<Device*>(ctx));
+    zx_status_t status = dev->coordinator->DriverCompatibiltyTest(dev);
+    return fuchsia_device_manager_CoordinatorRunCompatibilityTests_reply(txn, status);
+}
+
 static zx_status_t fidl_GetTopologicalPath(void* ctx, fidl_txn_t* txn) {
     char path[fuchsia_device_manager_DEVICE_PATH_MAX + 1];
 
diff --git a/zircon/system/core/devmgr/devhost/api.cpp b/zircon/system/core/devmgr/devhost/api.cpp
index 39c5946..9378557 100644
--- a/zircon/system/core/devmgr/devhost/api.cpp
+++ b/zircon/system/core/devmgr/devhost/api.cpp
@@ -221,6 +221,11 @@
     return devhost_device_unbind(dev);
 }
 
+zx_status_t device_run_compatibility_tests(const fbl::RefPtr<zx_device_t>& dev, const char* child_name) {
+    ApiAutoLock lock;
+    return devhost_device_run_compatibility_tests(dev, child_name);
+}
+
 zx_status_t device_open(const fbl::RefPtr<zx_device_t>& dev, fbl::RefPtr<zx_device_t>* out,
                         uint32_t flags) {
     ApiAutoLock lock;
diff --git a/zircon/system/core/devmgr/devhost/devhost.cpp b/zircon/system/core/devmgr/devhost/devhost.cpp
index c130604..3d05b91 100644
--- a/zircon/system/core/devmgr/devhost/devhost.cpp
+++ b/zircon/system/core/devmgr/devhost/devhost.cpp
@@ -819,6 +819,28 @@
     return call_status;
 }
 
+zx_status_t devhost_device_run_compatibility_tests(const fbl::RefPtr<zx_device_t>& dev,
+                                                   const char* child_name) REQ_DM_LOCK {
+    for (auto& child : dev->children) {
+        if (!strcmp(child.name, child_name)) {
+            const zx::channel& rpc = *child.rpc;
+            if (!rpc.is_valid()) {
+                return ZX_ERR_IO_REFUSED;
+            }
+            log_rpc(dev, "run-compatibility-test");
+            zx_status_t call_status;
+            zx_status_t status = fuchsia_device_manager_CoordinatorRunCompatibilityTests(
+                rpc.get(), &call_status);
+            log_rpc_result("run-compatibility-test", status, call_status);
+            if (status != ZX_OK) {
+                return status;
+            }
+            return call_status;
+        }
+    }
+    return ZX_ERR_INVALID_ARGS;
+}
+
 zx_status_t devhost_load_firmware(const fbl::RefPtr<zx_device_t>& dev, const char* path,
                                   zx_handle_t* vmo, size_t* size) {
     if ((vmo == nullptr) || (size == nullptr)) {
diff --git a/zircon/system/core/devmgr/devhost/devhost.h b/zircon/system/core/devmgr/devhost/devhost.h
index a153edd..03a55a0 100644
--- a/zircon/system/core/devmgr/devhost/devhost.h
+++ b/zircon/system/core/devmgr/devhost/devhost.h
@@ -136,6 +136,8 @@
                                 const char* drv_libname) REQ_DM_LOCK;
 zx_status_t devhost_device_rebind(const fbl::RefPtr<zx_device_t>& dev) REQ_DM_LOCK;
 zx_status_t devhost_device_unbind(const fbl::RefPtr<zx_device_t>& dev) REQ_DM_LOCK;
+zx_status_t devhost_device_run_compatibility_tests(const fbl::RefPtr<zx_device_t>& dev,
+                                                   const char* name) REQ_DM_LOCK;
 zx_status_t devhost_device_create(zx_driver_t* drv, const char* name, void* ctx,
                                   const zx_protocol_device_t* ops,
                                   fbl::RefPtr<zx_device_t>* out) REQ_DM_LOCK;
diff --git a/zircon/system/core/devmgr/devhost/device-controller-connection.cpp b/zircon/system/core/devmgr/devhost/device-controller-connection.cpp
index 8572853..5e07562 100644
--- a/zircon/system/core/devmgr/devhost/device-controller-connection.cpp
+++ b/zircon/system/core/devmgr/devhost/device-controller-connection.cpp
@@ -36,6 +36,11 @@
         bind_status = fuchsia_device_ControllerBind_reply(conn.Txn(), status);
     }
 
+    //TODO(ravoorir): Move completion to resume hook, when compatibility tests
+    //include suspend/resume tests.
+    if (dev->PopTestCompatibilityConn(&conn)) {
+        fuchsia_device_ControllerRunCompatibilityTests_reply(conn.Txn(), status);
+    }
     return bind_driver_status != ZX_OK ? bind_driver_status : bind_status;
 }
 
diff --git a/zircon/system/core/devmgr/devhost/rpc-server.cpp b/zircon/system/core/devmgr/devhost/rpc-server.cpp
index 9ec4e6d..3c780e5 100644
--- a/zircon/system/core/devmgr/devhost/rpc-server.cpp
+++ b/zircon/system/core/devmgr/devhost/rpc-server.cpp
@@ -576,6 +576,15 @@
     return device_bind(conn->dev, drv_libname);
 }
 
+static zx_status_t fidl_DeviceControllerRunCompatibilityTests(void* ctx, const char* child_data,
+                                                              size_t child_data_count, fidl_txn_t* txn) {
+    auto conn = static_cast<DevfsConnection*>(ctx);
+    char child_name[fuchsia_device_MAX_DEVICE_NAME_LEN + 1];
+    memcpy(child_name, child_data, child_data_count);
+    conn->dev->PushTestCompatibilityConn(fs::FidlConnection::CopyTxn(txn));
+    return device_run_compatibility_tests(conn->dev, child_name);
+}
+
 static zx_status_t fidl_DeviceControllerUnbind(void* ctx, fidl_txn_t* txn) {
     auto conn = static_cast<DevfsConnection*>(ctx);
     zx_status_t status = device_unbind(conn->dev);
@@ -672,6 +681,7 @@
     .SetDriverLogFlags = fidl_DeviceControllerSetDriverLogFlags,
     .DebugSuspend = fidl_DeviceControllerDebugSuspend,
     .DebugResume = fidl_DeviceControllerDebugResume,
+    .RunCompatibilityTests = fidl_DeviceControllerRunCompatibilityTests,
 };
 
 zx_status_t devhost_fidl_handler(fidl_msg_t* msg, fidl_txn_t* txn, void* cookie) {
diff --git a/zircon/system/core/devmgr/devhost/zx-device.cpp b/zircon/system/core/devmgr/devhost/zx-device.cpp
index e439120..27e09bc 100644
--- a/zircon/system/core/devmgr/devhost/zx-device.cpp
+++ b/zircon/system/core/devmgr/devhost/zx-device.cpp
@@ -30,6 +30,21 @@
     return true;
 }
 
+void zx_device::PushTestCompatibilityConn(const fs::FidlConnection& conn) {
+    fbl::AutoLock<fbl::Mutex> lock(&test_compatibility_conn_lock_);
+    test_compatibility_conn_.push_back(conn);
+}
+
+bool zx_device::PopTestCompatibilityConn(fs::FidlConnection* conn) {
+    fbl::AutoLock<fbl::Mutex> lock(&test_compatibility_conn_lock_);
+    if (test_compatibility_conn_.is_empty()) {
+        return false;
+    }
+    *conn = test_compatibility_conn_[0];
+    test_compatibility_conn_.erase(0);
+    return true;
+}
+
 // We must disable thread-safety analysis due to not being able to statically
 // guarantee the lock holding invariant.  Instead, we acquire the lock if
 // it's not already being held by the current thread.
diff --git a/zircon/system/core/devmgr/devhost/zx-device.h b/zircon/system/core/devmgr/devhost/zx-device.h
index 0a7e4c39..a4c7e0c 100644
--- a/zircon/system/core/devmgr/devhost/zx-device.h
+++ b/zircon/system/core/devmgr/devhost/zx-device.h
@@ -86,6 +86,9 @@
     void PushBindConn(const fs::FidlConnection& conn);
     bool PopBindConn(fs::FidlConnection* conn);
 
+    void PushTestCompatibilityConn(const fs::FidlConnection& conn);
+    bool PopTestCompatibilityConn(fs::FidlConnection* conn);
+
     // Check if this devhost has a device with the given ID, and if so returns a
     // reference to it.
     static fbl::RefPtr<zx_device> GetDeviceFromLocalId(uint64_t local_id);
@@ -197,6 +200,10 @@
     // The connection associated with a fuchsia.device.Controller/Bind.
     fbl::Mutex bind_conn_lock_;
     fbl::Vector<fs::FidlConnection> bind_conn_ TA_GUARDED(bind_conn_lock_);
+
+    // The connection associated with fuchsia.device.Controller/RunCompatibilityTests
+    fbl::Mutex test_compatibility_conn_lock_;
+    fbl::Vector<fs::FidlConnection> test_compatibility_conn_ TA_GUARDED(test_compatibility_conn_lock_);
 };
 
 // zx_device_t objects must be created or initialized by the driver manager's
@@ -222,6 +229,7 @@
 
 zx_status_t device_bind(const fbl::RefPtr<zx_device_t>& dev, const char* drv_libname);
 zx_status_t device_unbind(const fbl::RefPtr<zx_device_t>& dev);
+zx_status_t device_run_compatibility_tests(const fbl::RefPtr<zx_device_t>& dev, const char* child_name);
 zx_status_t device_open(const fbl::RefPtr<zx_device_t>& dev, fbl::RefPtr<zx_device_t>* out,
                         uint32_t flags);
 // Note that device_close() is intended to consume a reference (logically, the
diff --git a/zircon/system/dev/BUILD.gn b/zircon/system/dev/BUILD.gn
index 6280aae..dcb83d5 100644
--- a/zircon/system/dev/BUILD.gn
+++ b/zircon/system/dev/BUILD.gn
@@ -39,6 +39,8 @@
     "sysmem",
     "tee",
     "test/isolateddevmgr:isolateddevmgr-test",
+    "test/ddk-runcompatibilityhook:ddk-runcompatibilityhook-test",
+    "test/ddk-runcompatibilityhook:ddk-runcompatibilityhook-test-child",
     "test/mock-device",
     "test/sysdev",
     "thermal",
diff --git a/zircon/system/dev/test/BUILD.gn b/zircon/system/dev/test/BUILD.gn
index 3e0be90..66a9025 100644
--- a/zircon/system/dev/test/BUILD.gn
+++ b/zircon/system/dev/test/BUILD.gn
@@ -7,6 +7,7 @@
   deps = [
     "ddk-test",
     "isolateddevmgr",
+    "ddk-runcompatibilityhook",
     "mock-device",
     "operation",
     "sysdev",
diff --git a/zircon/system/dev/test/ddk-runcompatibilityhook/BUILD.gn b/zircon/system/dev/test/ddk-runcompatibilityhook/BUILD.gn
new file mode 100644
index 0000000..0870f4f
--- /dev/null
+++ b/zircon/system/dev/test/ddk-runcompatibilityhook/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright 2019 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.
+
+driver("ddk-runcompatibilityhook-test") {
+  sources = [
+    "test-driver.cpp",
+  ]
+  deps = [
+    "$zx/system/ulib/ddk",
+    "$zx/system/ulib/ddktl",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/zircon",
+  ]
+
+  # TODO(ZX-2863): This driver violates the allowed shlib deps policy.
+  deprecated_inhibit_driver_shlib_allowlist = true
+}
+
+driver("ddk-runcompatibilityhook-test-child") {
+  sources = [
+    "test-driver-child.cpp",
+  ]
+  deps = [
+    "$zx/system/ulib/ddk",
+    "$zx/system/ulib/ddktl",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/zircon",
+  ]
+
+  # TODO(ZX-2863): This driver violates the allowed shlib deps policy.
+  deprecated_inhibit_driver_shlib_allowlist = true
+}
+
+test("ddk-runcompatibilityhook") {
+  sources = [
+    "test.cpp",
+  ]
+  deps = [
+    "$zx/system/fidl/fuchsia-device:c",
+    "$zx/system/ulib/ddk",
+    "$zx/system/ulib/devmgr-integration-test",
+    "$zx/system/ulib/devmgr-launcher",
+    "$zx/system/ulib/driver-integration-test",
+    "$zx/system/ulib/fbl",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/zircon",
+    "$zx/system/ulib/zx",
+    "$zx/system/ulib/zxtest",
+  ]
+}
diff --git a/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver-child.cpp b/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver-child.cpp
new file mode 100644
index 0000000..f219c79
--- /dev/null
+++ b/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver-child.cpp
@@ -0,0 +1,59 @@
+// Copyright 2019 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 <vector>
+
+#include <ddk/binding.h>
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/platform-defs.h>
+#include <ddktl/device.h>
+#include <fbl/alloc_checker.h>
+
+class TestCompatibilityHookDriverChild;
+using DeviceType = ddk::Device<TestCompatibilityHookDriverChild, ddk::Unbindable>;
+class TestCompatibilityHookDriverChild : public DeviceType {
+public:
+    TestCompatibilityHookDriverChild(zx_device_t* parent)
+        : DeviceType(parent) {}
+    zx_status_t Bind();
+    void DdkUnbind() {
+        DdkRemove();
+    }
+    void DdkRelease() {
+        delete this;
+    }
+};
+
+zx_status_t TestCompatibilityHookDriverChild::Bind() {
+    return DdkAdd("compatibility-test-child");
+}
+
+zx_status_t test_compatibility_hook_child_bind(void* ctx, zx_device_t* device) {
+    fbl::AllocChecker ac;
+    auto dev = fbl::make_unique_checked<TestCompatibilityHookDriverChild>(&ac, device);
+    if (!ac.check()) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    auto status = dev->Bind();
+    if (status == ZX_OK) {
+        // devmgr is now in charge of the memory for dev
+        __UNUSED auto ptr = dev.release();
+    }
+    return status;
+}
+
+static zx_driver_ops_t test_compatibility_hook_child_driver_ops = []() -> zx_driver_ops_t {
+    zx_driver_ops_t ops;
+    ops.version = DRIVER_OPS_VERSION;
+    ops.bind = test_compatibility_hook_child_bind;
+    return ops;
+}();
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(TestCompatibilityHook, test_compatibility_hook_child_driver_ops, "zircon", "0.1", 4)
+    BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_TEST_CHILD),
+ZIRCON_DRIVER_END(TestCompatibilityHook)
+// clang-format on
diff --git a/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver.cpp b/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver.cpp
new file mode 100644
index 0000000..4419c17
--- /dev/null
+++ b/zircon/system/dev/test/ddk-runcompatibilityhook/test-driver.cpp
@@ -0,0 +1,62 @@
+// Copyright 2019 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 <vector>
+
+#include <ddk/binding.h>
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/platform-defs.h>
+#include <ddktl/device.h>
+#include <ddktl/protocol/empty-protocol.h>
+#include <fbl/alloc_checker.h>
+
+class TestCompatibilityHookDriver;
+using DeviceType = ddk::Device<TestCompatibilityHookDriver, ddk::Unbindable>;
+class TestCompatibilityHookDriver : public DeviceType,
+                                    public ddk::EmptyProtocol<ZX_PROTOCOL_TEST_CHILD> {
+public:
+    TestCompatibilityHookDriver(zx_device_t* parent)
+        : DeviceType(parent) {}
+    zx_status_t Bind();
+    void DdkUnbind() {
+        DdkRemove();
+    }
+    void DdkRelease() {
+        delete this;
+    }
+};
+
+zx_status_t TestCompatibilityHookDriver::Bind() {
+    return DdkAdd("compatibility-test");
+}
+
+zx_status_t test_compatibility_hook_bind(void* ctx, zx_device_t* device) {
+    fbl::AllocChecker ac;
+    auto dev = fbl::make_unique_checked<TestCompatibilityHookDriver>(&ac, device);
+    if (!ac.check()) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    auto status = dev->Bind();
+    if (status == ZX_OK) {
+        // devmgr is now in charge of the memory for dev
+        __UNUSED auto ptr = dev.release();
+    }
+    return status;
+}
+
+static zx_driver_ops_t test_compatibility_hook_driver_ops = []() -> zx_driver_ops_t {
+    zx_driver_ops_t ops;
+    ops.version = DRIVER_OPS_VERSION;
+    ops.bind = test_compatibility_hook_bind;
+    return ops;
+}();
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(TestCompatibilityHook, test_compatibility_hook_driver_ops, "zircon", "0.1", 4)
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_TEST),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_COMPATIBILITY_TEST),
+ZIRCON_DRIVER_END(TestCompatibilityHook)
+// clang-format on
diff --git a/zircon/system/dev/test/ddk-runcompatibilityhook/test.cpp b/zircon/system/dev/test/ddk-runcompatibilityhook/test.cpp
new file mode 100644
index 0000000..e7f1acd
--- /dev/null
+++ b/zircon/system/dev/test/ddk-runcompatibilityhook/test.cpp
@@ -0,0 +1,49 @@
+#include <ddk/platform-defs.h>
+#include <fuchsia/device/c/fidl.h>
+#include <lib/driver-integration-test/fixture.h>
+#include <lib/fdio/fd.h>
+#include <lib/fdio/fdio.h>
+#include <lib/fdio/namespace.h>
+#include <lib/fdio/spawn.h>
+#include <lib/fdio/unsafe.h>
+#include <lib/fdio/watcher.h>
+#include <zircon/processargs.h>
+#include <zircon/syscalls.h>
+#include <zxtest/zxtest.h>
+
+using driver_integration_test::IsolatedDevmgr;
+
+TEST(DeviceControllerIntegrationTest, RunCompatibilityHookSuccess) {
+    IsolatedDevmgr devmgr;
+    IsolatedDevmgr::Args args;
+    args.driver_search_paths.push_back("/boot/driver");
+    args.driver_search_paths.push_back("/boot/driver/test");
+
+    board_test::DeviceEntry dev = {};
+    dev.vid = PDEV_VID_TEST;
+    dev.pid = PDEV_PID_COMPATIBILITY_TEST;
+    dev.did = 0;
+    args.device_list.push_back(dev);
+
+    zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr);
+    ASSERT_OK(status);
+    fbl::unique_fd parent_fd, child_fd;
+    devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(),
+            "sys/platform/11:09:0/compatibility-test", &parent_fd);
+    ASSERT_GT(parent_fd.get(), 0);
+    //TODO(ravoorir): Why does this fail? Relative path waits do not work.
+    /*devmgr_integration_test::RecursiveWaitForFile(parent_fd,
+            "compatibility-test-child", &child_fd);
+    ASSERT_GT(child_fd.get(), 0);*/
+
+    zx::channel parent_device_handle;
+    ASSERT_EQ(ZX_OK, fdio_get_service_handle(parent_fd.release(),
+               parent_device_handle.reset_and_get_address()));
+    ASSERT_TRUE((parent_device_handle.get() != ZX_HANDLE_INVALID), "");
+
+    const char* child_name = "compatibility-test-child";
+    zx_status_t call_status;
+    status = fuchsia_device_ControllerRunCompatibilityTests(parent_device_handle.get(), child_name, strlen(child_name), &call_status);
+    ASSERT_OK(status);
+    ASSERT_OK(call_status);
+}
diff --git a/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl b/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl
index 7afcce1..69f4833 100644
--- a/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl
+++ b/zircon/system/fidl/fuchsia-device-manager/coordinator.fidl
@@ -219,4 +219,7 @@
     /// See fuchsia.io.Directory for more information.
     DirectoryWatch(uint32 mask, uint32 options, handle<channel> watcher)
         -> (zx.status s);
+
+    /// Run Compatibility tests
+    RunCompatibilityTests() -> (zx.status status);
 };
diff --git a/zircon/system/fidl/fuchsia-device/controller.fidl b/zircon/system/fidl/fuchsia-device/controller.fidl
index d2ef6f7..03b4508 100644
--- a/zircon/system/fidl/fuchsia-device/controller.fidl
+++ b/zircon/system/fidl/fuchsia-device/controller.fidl
@@ -62,4 +62,8 @@
     DebugSuspend() -> (zx.status status);
     /// Debug command: execute the device's resume hook
     DebugResume() -> (zx.status status);
+
+    /// RunCompatibilityTests: Run compatibility test on the driver that added
+    /// this device.
+    RunCompatibilityTests(string:MAX_DEVICE_NAME_LEN child_name) -> (zx.status status);
 };
diff --git a/zircon/system/ulib/ddk/include/ddk/platform-defs.h b/zircon/system/ulib/ddk/include/ddk/platform-defs.h
index f339673..8122f2f 100644
--- a/zircon/system/ulib/ddk/include/ddk/platform-defs.h
+++ b/zircon/system/ulib/ddk/include/ddk/platform-defs.h
@@ -193,6 +193,7 @@
 #define PDEV_PID_LIBDRIVER_TEST     6
 #define PDEV_PID_METADATA_TEST      7
 #define PDEV_PID_PCI_TEST           8
+#define PDEV_PID_COMPATIBILITY_TEST 9
 
 #define PDEV_DID_TEST_PARENT        1
 #define PDEV_DID_TEST_CHILD_1       2
diff --git a/zircon/system/ulib/ddk/include/ddk/protodefs.h b/zircon/system/ulib/ddk/include/ddk/protodefs.h
index 4118ceb..724697e 100644
--- a/zircon/system/ulib/ddk/include/ddk/protodefs.h
+++ b/zircon/system/ulib/ddk/include/ddk/protodefs.h
@@ -86,6 +86,7 @@
 DDK_PROTOCOL_DEF(IHDA_DSP,       'piHD', "intel-hda-dsp", 0)
 DDK_PROTOCOL_DEF(AUDIO_CODEC,    'pAUC', "audio-codec", 0)
 DDK_PROTOCOL_DEF(TEST,           'pTST', "test", 0)
+DDK_PROTOCOL_DEF(TEST_CHILD,     'pTCC', "test-child", 0)
 DDK_PROTOCOL_DEF(TEST_PARENT,    'pTSP', "test-parent", PF_NOPUB)
 DDK_PROTOCOL_DEF(PBUS,           'pPBU', "platform-bus", 0)
 DDK_PROTOCOL_DEF(PDEV,           'pPDV', "platform-dev", 0)