diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index cc2b5b084dc42e4caaa39e73ed06c3f2aaca2075..c836c0196b2206ce42e86d96e3ec31848c650849 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -45,6 +45,9 @@ set(SRCS
             hle/service/gsp_gpu.cpp
             hle/service/hid/hid.cpp
             hle/service/lm/lm.cpp
+            hle/service/nvdrv/devices/nvdisp_disp0.cpp
+            hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+            hle/service/nvdrv/devices/nvmap.cpp
             hle/service/nvdrv/nvdrv.cpp
             hle/service/nvdrv/nvdrv_a.cpp
             hle/service/pctl/pctl.cpp
@@ -132,6 +135,10 @@ set(HEADERS
             hle/service/gsp_gpu.h
             hle/service/hid/hid.h
             hle/service/lm/lm.h
+            hle/service/nvdrv/devices/nvdevice.h
+            hle/service/nvdrv/devices/nvdisp_disp0.h
+            hle/service/nvdrv/devices/nvhost_as_gpu.h
+            hle/service/nvdrv/devices/nvmap.h
             hle/service/nvdrv/nvdrv.h
             hle/service/nvdrv/nvdrv_a.h
             hle/service/pctl/pctl.h
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4efce3a162e3fc050bd43bb99070a07d36eff75
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -0,0 +1,33 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+/// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to
+/// implement the ioctl interface.
+class nvdevice {
+public:
+    nvdevice() = default;
+    virtual ~nvdevice() = default;
+
+    /**
+     * Handles an ioctl request.
+     * @param command The ioctl command id.
+     * @param input A buffer containing the input data for the ioctl.
+     * @param output A buffer where the output data will be written to.
+     * @returns The result code of the ioctl.
+     */
+    virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
+};
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..faed626baeae8bbbee0445f76501154347fc20dc
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -0,0 +1,29 @@
+// Copyright 2018 Yuzu Emulator Team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
+#include "core/hle/service/nvdrv/devices/nvmap.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+u32 nvdisp_disp0::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
+    ASSERT(false, "Unimplemented");
+    return 0;
+}
+
+void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
+                        u32 stride) {
+    VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
+    LOG_WARNING(Service,
+                "Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
+                addr, offset, width, height, stride, format);
+}
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
new file mode 100644
index 0000000000000000000000000000000000000000..54725917fc7616b562174c507a10892902405db9
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -0,0 +1,34 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+class nvmap;
+
+class nvdisp_disp0 final : public nvdevice {
+public:
+    nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {}
+    ~nvdisp_disp0() = default;
+
+    u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+    /// Performs a screen flip, drawing the buffer pointed to by the handle.
+    void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride);
+
+private:
+    std::shared_ptr<nvmap> nvmap_dev;
+};
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..50fee8f46e138ba14da7f51a12eaad553902832c
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -0,0 +1,20 @@
+// Copyright 2018 Yuzu Emulator Team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+u32 nvhost_as_gpu::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
+    ASSERT(false, "Unimplemented");
+    return 0;
+}
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..4112759229b157326279697033eadc958e9b56c1
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -0,0 +1,25 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+class nvhost_as_gpu final : public nvdevice {
+public:
+    nvhost_as_gpu() = default;
+    ~nvhost_as_gpu() override = default;
+
+    u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
+};
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fdf2f7be5ea2e176f6842450009419f43d338415
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -0,0 +1,153 @@
+// Copyright 2018 Yuzu Emulator Team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvmap.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+VAddr nvmap::GetObjectAddress(u32 handle) const {
+    auto itr = handles.find(handle);
+    ASSERT(itr != handles.end());
+
+    auto object = itr->second;
+    ASSERT(object->status == Object::Status::Allocated);
+    return object->addr;
+}
+
+u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
+    switch (command) {
+    case IocCreateCommand:
+        return IocCreate(input, output);
+    case IocAllocCommand:
+        return IocAlloc(input, output);
+    case IocGetIdCommand:
+        return IocGetId(input, output);
+    case IocFromIdCommand:
+        return IocFromId(input, output);
+    case IocParamCommand:
+        return IocParam(input, output);
+    }
+
+    ASSERT(false, "Unimplemented");
+}
+
+u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
+    IocCreateParams params;
+    std::memcpy(&params, input.data(), sizeof(params));
+
+    // Create a new nvmap object and obtain a handle to it.
+    auto object = std::make_shared<Object>();
+    object->id = next_id++;
+    object->size = params.size;
+    object->status = Object::Status::Created;
+
+    u32 handle = next_handle++;
+    handles[handle] = std::move(object);
+
+    LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size);
+
+    params.handle = handle;
+
+    std::memcpy(output.data(), &params, sizeof(params));
+    return 0;
+}
+
+u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
+    IocAllocParams params;
+    std::memcpy(&params, input.data(), sizeof(params));
+
+    auto itr = handles.find(params.handle);
+    ASSERT(itr != handles.end());
+
+    auto object = itr->second;
+    object->flags = params.flags;
+    object->align = params.align;
+    object->kind = params.kind;
+    object->addr = params.addr;
+    object->status = Object::Status::Allocated;
+
+    LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr);
+
+    std::memcpy(output.data(), &params, sizeof(params));
+    return 0;
+}
+
+u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
+    IocGetIdParams params;
+    std::memcpy(&params, input.data(), sizeof(params));
+
+    LOG_WARNING(Service, "called");
+
+    auto itr = handles.find(params.handle);
+    ASSERT(itr != handles.end());
+
+    params.id = itr->second->id;
+
+    std::memcpy(output.data(), &params, sizeof(params));
+    return 0;
+}
+
+u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
+    IocFromIdParams params;
+    std::memcpy(&params, input.data(), sizeof(params));
+
+    LOG_WARNING(Service, "(STUBBED) called");
+
+    auto itr = std::find_if(handles.begin(), handles.end(),
+                            [&](const auto& entry) { return entry.second->id == params.id; });
+    ASSERT(itr != handles.end());
+
+    // Make a new handle for the object
+    u32 handle = next_handle++;
+    handles[handle] = itr->second;
+
+    params.handle = handle;
+
+    std::memcpy(output.data(), &params, sizeof(params));
+    return 0;
+}
+
+u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
+    enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
+
+    IocParamParams params;
+    std::memcpy(&params, input.data(), sizeof(params));
+
+    LOG_WARNING(Service, "(STUBBED) called type=%u", params.type);
+
+    auto itr = handles.find(params.handle);
+    ASSERT(itr != handles.end());
+
+    auto object = itr->second;
+    ASSERT(object->status == Object::Status::Allocated);
+
+    switch (static_cast<ParamTypes>(params.type)) {
+    case ParamTypes::Size:
+        params.value = object->size;
+        break;
+    case ParamTypes::Alignment:
+        params.value = object->align;
+        break;
+    case ParamTypes::Heap:
+        // TODO(Subv): Seems to be a hardcoded value?
+        params.value = 0x40000000;
+        break;
+    case ParamTypes::Kind:
+        params.value = object->kind;
+        break;
+    default:
+        ASSERT(false, "Unimplemented");
+    }
+
+    std::memcpy(output.data(), &params, sizeof(params));
+    return 0;
+}
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8b08f3fb33bcc3e06b90df880ee83c33887bb75
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -0,0 +1,108 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service {
+namespace NVDRV {
+namespace Devices {
+
+class nvmap final : public nvdevice {
+public:
+    nvmap() = default;
+    ~nvmap() override = default;
+
+    /// Returns the allocated address of an nvmap object given its handle.
+    VAddr GetObjectAddress(u32 handle) const;
+
+    u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+private:
+    // Represents an nvmap object.
+    struct Object {
+        enum class Status { Created, Allocated };
+        u32 id;
+        u32 size;
+        u32 flags;
+        u32 align;
+        u8 kind;
+        VAddr addr;
+        Status status;
+    };
+
+    /// Id to use for the next handle that is created.
+    u32 next_handle = 1;
+
+    // Id to use for the next object that is created.
+    u32 next_id = 1;
+
+    /// Mapping of currently allocated handles to the objects they represent.
+    std::unordered_map<u32, std::shared_ptr<Object>> handles;
+
+    enum IoctlCommands {
+        IocCreateCommand = 0xC0080101,
+        IocFromIdCommand = 0xC0080103,
+        IocAllocCommand = 0xC0200104,
+        IocParamCommand = 0xC00C0109,
+        IocGetIdCommand = 0xC008010E
+    };
+
+    struct IocCreateParams {
+        // Input
+        u32_le size;
+        // Output
+        u32_le handle;
+    };
+
+    struct IocAllocParams {
+        // Input
+        u32_le handle;
+        u32_le heap_mask;
+        u32_le flags;
+        u32_le align;
+        u8 kind;
+        INSERT_PADDING_BYTES(7);
+        u64_le addr;
+    };
+
+    struct IocGetIdParams {
+        // Output
+        u32_le id;
+        // Input
+        u32_le handle;
+    };
+
+    struct IocFromIdParams {
+        // Input
+        u32_le id;
+        // Output
+        u32_le handle;
+    };
+
+    struct IocParamParams {
+        // Input
+        u32_le handle;
+        u32_le type;
+        // Output
+        u32_le value;
+    };
+
+    u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
+    u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
+    u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
+    u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
+    u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
+};
+
+} // namespace Devices
+} // namespace NVDRV
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.cpp b/src/core/hle/service/nvdrv/nvdrv_a.cpp
index cede4a883f1c6fbbf2b1e338e2b0b2d5a9f8e295..cfecea924783f13dc9d28fc9a897112367c66431 100644
--- a/src/core/hle/service/nvdrv/nvdrv_a.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_a.cpp
@@ -4,171 +4,16 @@
 
 #include "common/logging/log.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
+#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
+#include "core/hle/service/nvdrv/devices/nvmap.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
 #include "core/hle/service/nvdrv/nvdrv_a.h"
 
 namespace Service {
 namespace NVDRV {
 
-class nvhost_as_gpu : public nvdevice {
-public:
-    u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override {
-        ASSERT(false, "Unimplemented");
-        return 0;
-    }
-};
-
-VAddr nvmap::GetObjectAddress(u32 handle) const {
-    auto itr = handles.find(handle);
-    ASSERT(itr != handles.end());
-
-    auto object = itr->second;
-    ASSERT(object->status == Object::Status::Allocated);
-    return object->addr;
-}
-
-u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
-    switch (command) {
-    case IocCreateCommand:
-        return IocCreate(input, output);
-    case IocAllocCommand:
-        return IocAlloc(input, output);
-    case IocGetIdCommand:
-        return IocGetId(input, output);
-    case IocFromIdCommand:
-        return IocFromId(input, output);
-    case IocParamCommand:
-        return IocParam(input, output);
-    }
-
-    ASSERT(false, "Unimplemented");
-}
-
-u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
-    IocCreateParams params;
-    std::memcpy(&params, input.data(), sizeof(params));
-
-    // Create a new nvmap object and obtain a handle to it.
-    auto object = std::make_shared<Object>();
-    object->id = next_id++;
-    object->size = params.size;
-    object->status = Object::Status::Created;
-
-    u32 handle = next_handle++;
-    handles[handle] = std::move(object);
-
-    LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size);
-
-    params.handle = handle;
-
-    std::memcpy(output.data(), &params, sizeof(params));
-    return 0;
-}
-
-u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
-    IocAllocParams params;
-    std::memcpy(&params, input.data(), sizeof(params));
-
-    auto itr = handles.find(params.handle);
-    ASSERT(itr != handles.end());
-
-    auto object = itr->second;
-    object->flags = params.flags;
-    object->align = params.align;
-    object->kind = params.kind;
-    object->addr = params.addr;
-    object->status = Object::Status::Allocated;
-
-    LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr);
-
-    std::memcpy(output.data(), &params, sizeof(params));
-    return 0;
-}
-
-u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
-    IocGetIdParams params;
-    std::memcpy(&params, input.data(), sizeof(params));
-
-    LOG_WARNING(Service, "called");
-
-    auto itr = handles.find(params.handle);
-    ASSERT(itr != handles.end());
-
-    params.id = itr->second->id;
-
-    std::memcpy(output.data(), &params, sizeof(params));
-    return 0;
-}
-
-u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
-    IocFromIdParams params;
-    std::memcpy(&params, input.data(), sizeof(params));
-
-    LOG_WARNING(Service, "(STUBBED) called");
-
-    auto itr = std::find_if(handles.begin(), handles.end(),
-                            [&](const auto& entry) { return entry.second->id == params.id; });
-    ASSERT(itr != handles.end());
-
-    // Make a new handle for the object
-    u32 handle = next_handle++;
-    handles[handle] = itr->second;
-
-    params.handle = handle;
-
-    std::memcpy(output.data(), &params, sizeof(params));
-    return 0;
-}
-
-u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
-    enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
-
-    IocParamParams params;
-    std::memcpy(&params, input.data(), sizeof(params));
-
-    LOG_WARNING(Service, "(STUBBED) called type=%u", params.type);
-
-    auto itr = handles.find(params.handle);
-    ASSERT(itr != handles.end());
-
-    auto object = itr->second;
-    ASSERT(object->status == Object::Status::Allocated);
-
-    switch (static_cast<ParamTypes>(params.type)) {
-    case ParamTypes::Size:
-        params.value = object->size;
-        break;
-    case ParamTypes::Alignment:
-        params.value = object->align;
-        break;
-    case ParamTypes::Heap:
-        // TODO(Subv): Seems to be a hardcoded value?
-        params.value = 0x40000000;
-        break;
-    case ParamTypes::Kind:
-        params.value = object->kind;
-        break;
-    default:
-        ASSERT(false, "Unimplemented");
-    }
-
-    std::memcpy(output.data(), &params, sizeof(params));
-    return 0;
-}
-
-u32 nvdisp_disp0::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
-    ASSERT(false, "Unimplemented");
-    return 0;
-}
-
-void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
-                        u32 stride) {
-    VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
-    LOG_WARNING(Service,
-                "Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
-                addr, offset, width, height, stride, format);
-}
-
 void NVDRV_A::Open(Kernel::HLERequestContext& ctx) {
     LOG_WARNING(Service, "(STUBBED) called");
 
@@ -229,10 +74,10 @@ NVDRV_A::NVDRV_A() : ServiceFramework("nvdrv:a") {
     };
     RegisterHandlers(functions);
 
-    auto nvmap_dev = std::make_shared<nvmap>();
-    devices["/dev/nvhost-as-gpu"] = std::make_shared<nvhost_as_gpu>();
+    auto nvmap_dev = std::make_shared<Devices::nvmap>();
+    devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>();
     devices["/dev/nvmap"] = nvmap_dev;
-    devices["/dev/nvdisp_disp0"] = std::make_shared<nvdisp_disp0>(nvmap_dev);
+    devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
 }
 
 } // namespace NVDRV
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.h b/src/core/hle/service/nvdrv/nvdrv_a.h
index af101788166fa8457fde0e5a02b9c8e524420a5a..4cd04adeaa78f91f5227ade0916f796152a0fc49 100644
--- a/src/core/hle/service/nvdrv/nvdrv_a.h
+++ b/src/core/hle/service/nvdrv/nvdrv_a.h
@@ -5,12 +5,17 @@
 #pragma once
 
 #include <memory>
-#include "core/hle/service/service.h"
+#include <string>
 #include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/service.h"
 
 namespace Service {
 namespace NVDRV {
 
+namespace Devices {
+class nvdevice;
+}
+
 class NVDRV_A final : public ServiceFramework<NVDRV_A> {
 public:
     NVDRV_A();
@@ -30,10 +35,14 @@ private:
     void Ioctl(Kernel::HLERequestContext& ctx);
     void Initialize(Kernel::HLERequestContext& ctx);
 
+    /// Id to use for the next open file descriptor.
     u32 next_fd = 1;
 
-    std::unordered_map<u32, std::shared_ptr<nvdevice>> open_files;
-    std::unordered_map<std::string, std::shared_ptr<nvdevice>> devices;
+    /// Mapping of file descriptors to the devices they reference.
+    std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files;
+
+    /// Mapping of device node names to their implementation.
+    std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
 };
 
 extern std::weak_ptr<NVDRV_A> nvdrv_a;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 55bbd45db7d4cc48316bea48f495469450997b8f..0b089702c2559b6b4e2d0d61a5e9d4712aff19f1 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -6,6 +6,7 @@
 #include "common/scope_exit.h"
 #include "core/core_timing.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
 #include "core/hle/service/nvdrv/nvdrv_a.h"
 #include "core/hle/service/vi/vi.h"
 #include "core/hle/service/vi/vi_m.h"
@@ -752,7 +753,7 @@ void NVFlinger::Compose() {
 
         // TODO(Subv): Support more than just disp0. The display device selection is probably based
         // on which display we're drawing (Default, Internal, External, etc)
-        auto nvdisp = nvdrv->GetDevice<NVDRV::nvdisp_disp0>("/dev/nvdisp_disp0");
+        auto nvdisp = nvdrv->GetDevice<NVDRV::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
         ASSERT(nvdisp);
 
         nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,