// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include "common/concepts.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service::Nvidia::Devices { struct Ioctl1Traits { template static T GetClassImpl(R (T::*)(A)); template static A GetArgImpl(R (T::*)(A)); }; struct Ioctl23Traits { template static T GetClassImpl(R (T::*)(A, B)); template static A GetArgImpl(R (T::*)(A, B)); }; template struct ContainerType { using ValueType = T; }; template struct ContainerType { using ValueType = T::value_type; }; template NvResult Wrap(std::span input, std::span output, Self* self, F&& callable, Rest&&... rest) { using Arg = ContainerType::ValueType; constexpr bool ArgumentIsContainer = Common::IsContiguousContainer; // Verify that the input and output sizes are valid. const size_t in_params = input.size() / sizeof(Arg); const size_t out_params = output.size() / sizeof(Arg); if (in_params * sizeof(Arg) != input.size()) { return NvResult::InvalidSize; } if (out_params * sizeof(Arg) != output.size()) { return NvResult::InvalidSize; } if (in_params == 0 && out_params == 0 && !ArgumentIsContainer) { return NvResult::InvalidSize; } // Copy inputs, if needed. std::vector params(std::max(in_params, out_params)); if (in_params > 0) { std::memcpy(params.data(), input.data(), input.size()); } // Perform the call. NvResult result; if constexpr (ArgumentIsContainer) { result = (self->*callable)(params, std::forward(rest)...); } else { result = (self->*callable)(params.front(), std::forward(rest)...); } // Copy outputs, if needed. if (out_params > 0) { std::memcpy(output.data(), params.data(), output.size()); } return result; } template NvResult nvdevice::Wrap1(F&& callable, std::span input, std::span output) { using Self = decltype(Ioctl1Traits::GetClassImpl(callable)); using InnerArg = std::remove_reference_t; return Wrap(input, output, static_cast(this), callable); } template NvResult nvdevice::Wrap2(F&& callable, std::span input, std::span inline_input, std::span output) { using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); using InnerArg = std::remove_reference_t; return Wrap(input, output, static_cast(this), callable, inline_input); } template NvResult nvdevice::Wrap3(F&& callable, std::span input, std::span output, std::span inline_output) { using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); using InnerArg = std::remove_reference_t; return Wrap(input, output, static_cast(this), callable, inline_output); } } // namespace Service::Nvidia::Devices