diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index b46e6193db..8a4bbc2f5c 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -458,10 +458,49 @@ namespace Ryujinx.HLE.HOS.Services.Nv } [Command(12)] // 3.0.0+ - // Ioctl2(s32 fd, u32 ioctl_cmd, buffer in_args) -> (u32 error_code, buffer out_args, buffer out_additional_buffer) + // Ioctl3(s32 fd, u32 ioctl_cmd, buffer in_args) -> (u32 error_code, buffer out_args, buffer inline_out_buffer) public ResultCode Ioctl3(ServiceCtx context) { - throw new ServiceNotImplementedException(context); + NvResult errorCode = EnsureInitialized(); + + if (errorCode == NvResult.Success) + { + int fd = context.RequestData.ReadInt32(); + NvIoctl ioctlCommand = context.RequestData.ReadStruct(); + + (long inlineOutBufferPosition, long inlineOutBufferSize) = context.Request.GetBufferType0x22(1); + + errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); + + Span inlineOutBuffer = new Span(context.Memory.ReadBytes(inlineOutBufferPosition, inlineOutBufferSize)); + + if (errorCode == NvResult.Success) + { + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + NvInternalResult internalResult = fileDevice.Ioctl3(ioctlCommand, arguments, inlineOutBuffer); + + if (internalResult == NvInternalResult.NotImplemented) + { + throw new NvIoctlNotImplementedException(context, fileDevice, ioctlCommand); + } + + errorCode = ConvertInternalErrorCode(internalResult); + + if (errorCode == NvResult.Success && (ioctlCommand.GetDirectionValue() & NvIoctl.Direction.Write) != 0) + { + context.Memory.WriteBytes(context.Request.GetBufferType0x22(0).Position, arguments.ToArray()); + context.Memory.WriteBytes(inlineOutBufferPosition, inlineOutBuffer.ToArray()); + } + } + } + } + + context.ResponseData.Write((uint)errorCode); + + return ResultCode.Success; } [Command(13)] // 3.0.0+ diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs index 4d52cfe130..03108ca7b9 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs @@ -50,18 +50,22 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices protected delegate NvInternalResult IoctlProcessor(ref T arguments); protected delegate NvInternalResult IoctlProcessorSpan(Span arguments); - protected delegate NvInternalResult IoctlProcessorInline(ref T arguments, Span inlineData); + protected delegate NvInternalResult IoctlProcessorInline(ref T arguments, ref Y inlineData); + protected delegate NvInternalResult IoctlProcessorInlineSpan(ref T arguments, Span inlineData); protected static NvInternalResult CallIoctlMethod(IoctlProcessor callback, Span arguments) where T : struct { Debug.Assert(arguments.Length == Unsafe.SizeOf()); + return callback(ref MemoryMarshal.Cast(arguments)[0]); } - protected static NvInternalResult CallIoctlMethod(IoctlProcessorInline callback, Span arguments, Span inlineInBuffer) where T : struct where Y : struct + protected static NvInternalResult CallIoctlMethod(IoctlProcessorInline callback, Span arguments, Span inlineBuffer) where T : struct where Y : struct { Debug.Assert(arguments.Length == Unsafe.SizeOf()); - return callback(ref MemoryMarshal.Cast(arguments)[0], MemoryMarshal.Cast(inlineInBuffer)); + Debug.Assert(inlineBuffer.Length == Unsafe.SizeOf()); + + return callback(ref MemoryMarshal.Cast(arguments)[0], ref MemoryMarshal.Cast(inlineBuffer)[0]); } protected static NvInternalResult CallIoctlMethod(IoctlProcessorSpan callback, Span arguments) where T : struct @@ -69,6 +73,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices return callback(MemoryMarshal.Cast(arguments)); } + protected static NvInternalResult CallIoctlMethod(IoctlProcessorInlineSpan callback, Span arguments, Span inlineBuffer) where T : struct where Y : struct + { + Debug.Assert(arguments.Length == Unsafe.SizeOf()); + + return callback(ref MemoryMarshal.Cast(arguments)[0], MemoryMarshal.Cast(inlineBuffer)); + } + public abstract void Close(); } }