Add MsdImgDevice

Change-Id: I6f921212dc9092759d6de8876e5540ce34b41c58
diff --git a/BUILD.gn b/BUILD.gn
index 07fe15b..a41f1ea 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -134,6 +134,7 @@
 
   sources += [
     "fuchsia/msd_entrypoints.cc",
+    "fuchsia/msd_img_device.cc",
     "fuchsia/msd_img_driver.cc",
   ]
 
@@ -208,6 +209,7 @@
   deps = [
     "//garnet/lib/magma/include:msd_abi",
     "//garnet/lib/magma/src/magma_util",
+    "//garnet/lib/magma/src/magma_util/platform:device",
     "//zircon/public/lib/zx",
   ]
 }
diff --git a/fuchsia/msd_entrypoints.cc b/fuchsia/msd_entrypoints.cc
index 6f1e86d..f528314 100644
--- a/fuchsia/msd_entrypoints.cc
+++ b/fuchsia/msd_entrypoints.cc
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include "msd.h"
 
+#include "msd_img_device.h"
 #include "msd_img_driver.h"
 
 msd_driver_t*
@@ -29,12 +30,13 @@
 msd_device_t*
 msd_driver_create_device(msd_driver_t* drv, void* device)
 {
-	return nullptr;
+	return MsdImgDevice::Create(drv, device).release();
 }
 
 void
 msd_device_destroy(msd_device_t* dev)
 {
+	MsdImgDevice::Destroy(MsdImgDevice::cast(dev));
 }
 
 magma_status_t
diff --git a/fuchsia/msd_img_device.cc b/fuchsia/msd_img_device.cc
new file mode 100644
index 0000000..c210f6b
--- /dev/null
+++ b/fuchsia/msd_img_device.cc
@@ -0,0 +1,78 @@
+// 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 "msd_img_device.h"
+
+extern "C"
+{
+#include "process_stats.h"
+#include "pvrsrv.h"
+#include "pvrsrv_error.h"
+#include "rgxdevice.h"
+#include "srvcore.h"
+}
+
+
+MsdImgDevice::MsdImgDevice(std::unique_ptr<magma::PlatformDevice> platform_device)
+	     : platform_device_(std::move(platform_device))
+{
+	magic_ = kMagic;
+}
+
+MsdImgDevice::~MsdImgDevice()
+{
+	if (device_node_)
+	{
+		PVRSRVDeviceDestroy(device_node_);
+	}
+}
+
+bool
+MsdImgDevice::Init()
+{
+	bti_ = platform_device_->GetBusTransactionInitiator();
+	if (!bti_)
+	{
+		return DRETF(false, "Failed to create bus transaction initiator");
+	}
+
+	PVRSRV_ERROR srv_err;
+	srv_err = PVRSRVDeviceCreate(this, 1u, &device_node_);
+	if (srv_err != PVRSRV_OK)
+	{
+		return DRETF(false, "Failed to create device: %d", srv_err);
+	}
+
+	srv_err = PVRSRVDeviceInitialise(device_node_);
+	if (srv_err != PVRSRV_OK)
+	{
+		return DRETF(false, "Failed to initialize device: %d", srv_err);
+	}
+	return true;
+}
+
+// static
+std::unique_ptr<MsdImgDevice>
+MsdImgDevice::Create(msd_driver_t* drv, void* device)
+{
+	auto platform_device = magma::PlatformDevice::Create(device);
+	if (!platform_device)
+	{
+		return DRETP(nullptr, "Failed to create platform device");
+	}
+
+	auto msd_device = std::unique_ptr<MsdImgDevice>(new MsdImgDevice(std::move(platform_device)));
+	if (!msd_device->Init())
+	{
+		return DRETP(nullptr, "Failed to create msd device");
+	}
+	return msd_device;
+}
+
+// static
+void
+MsdImgDevice::Destroy(MsdImgDevice* device)
+{
+	delete device;
+}
diff --git a/fuchsia/msd_img_device.h b/fuchsia/msd_img_device.h
new file mode 100644
index 0000000..795f9ee
--- /dev/null
+++ b/fuchsia/msd_img_device.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef MSD_IMG_DEVICE_H
+#define MSD_IMG_DEVICE_H
+
+#include <memory>
+
+#include "magma_util/macros.h"
+#include "msd.h"
+#include "platform_device.h"
+
+typedef struct _PVRSRV_DEVICE_NODE_ PVRSRV_DEVICE_NODE;
+
+class MsdImgDevice : public msd_device_t
+{
+public:
+	virtual ~MsdImgDevice();
+
+	static std::unique_ptr<MsdImgDevice> Create(struct msd_driver_t* drv, void* device);
+
+	bool Init();
+
+	static void Destroy(MsdImgDevice* drv);
+
+	static MsdImgDevice* cast(msd_device_t* drv)
+	{
+		DASSERT(drv);
+		DASSERT(drv->magic_ == kMagic);
+		return static_cast<MsdImgDevice*>(drv);
+	}
+
+	magma::PlatformHandle* bti() { return bti_.get(); }
+
+private:
+	MsdImgDevice(std::unique_ptr<magma::PlatformDevice>);
+
+	static const uint32_t kMagic = 'idev';
+
+	std::unique_ptr<magma::PlatformDevice> platform_device_;
+	std::unique_ptr<magma::PlatformHandle> bti_;
+	PVRSRV_DEVICE_NODE* device_node_ = nullptr;
+};
+
+#endif // MSD_IMG_DEVICE_H