// SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-FileCopyrightText: 2021 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/nvdrv/core/container.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/nvhost_ctrl.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/nvdrv/nvmemp.h" #include "core/hle/service/nvflinger/nvflinger.h" #include "video_core/gpu.h" namespace Service::Nvidia { EventInterface::EventInterface(Module& module_) : module{module_}, guard{}, on_signal{} {} EventInterface::~EventInterface() = default; Kernel::KEvent* EventInterface::CreateEvent(std::string name) { Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); return new_event; } void EventInterface::FreeEvent(Kernel::KEvent* event) { module.service_context.CloseEvent(event); } void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, Core::System& system) { auto module_ = std::make_shared(system); std::make_shared(system, module_, "nvdrv")->InstallAsService(service_manager); std::make_shared(system, module_, "nvdrv:a")->InstallAsService(service_manager); std::make_shared(system, module_, "nvdrv:s")->InstallAsService(service_manager); std::make_shared(system, module_, "nvdrv:t")->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); nvflinger.SetNVDrvInstance(module_); } Module::Module(Core::System& system) : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, *this, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, events_interface, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, events_interface); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, events_interface, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, container); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system); return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { auto device = std::make_shared(system, container); return open_files.emplace(fd, std::move(device)).first; }; } Module::~Module() {} NvResult Module::VerifyFD(DeviceFD fd) const { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } if (open_files.find(fd) == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } return NvResult::Success; } DeviceFD Module::Open(const std::string& device_name) { auto it = builders.find(device_name); if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); return INVALID_NVDRV_FD; } const DeviceFD fd = next_fd++; auto& builder = it->second; auto device = builder(fd)->second; device->OnOpen(fd); return fd; } NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span input, std::vector& output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } const auto itr = open_files.find(fd); if (itr == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } return itr->second->Ioctl1(fd, command, input, output); } NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span input, std::span inline_input, std::vector& output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } const auto itr = open_files.find(fd); if (itr == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } return itr->second->Ioctl2(fd, command, input, inline_input, output); } NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, std::vector& inline_output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } const auto itr = open_files.find(fd); if (itr == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } return itr->second->Ioctl3(fd, command, input, output, inline_output); } NvResult Module::Close(DeviceFD fd) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } const auto itr = open_files.find(fd); if (itr == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } itr->second->OnClose(fd); open_files.erase(itr); return NvResult::Success; } NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; } const auto itr = open_files.find(fd); if (itr == open_files.end()) { LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); return NvResult::NotImplemented; } event = itr->second->QueryEvent(event_id); if (!event) { return NvResult::BadParameter; } return NvResult::Success; } } // namespace Service::Nvidia