mm: Migrate service in Horizon project (#5580)
* mm: Migrate service in Horizon project This PR migrate the `mm:u` service to the Horizon project, things were checked by some RE aswell, that's why some vars are renamed, the logic should be the same as before. Tests are welcome. * Lock _sessionList instead * Fix comment * Fix Session fields order
This commit is contained in:
parent
6ed613a6e6
commit
b0b7843d5c
@ -1,196 +0,0 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Mm.Types;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Mm
|
|
||||||
{
|
|
||||||
[Service("mm:u")]
|
|
||||||
class IRequest : IpcService
|
|
||||||
{
|
|
||||||
private readonly object _sessionListLock = new();
|
|
||||||
private readonly List<MultiMediaSession> _sessionList = new();
|
|
||||||
|
|
||||||
private uint _uniqueId = 1;
|
|
||||||
|
|
||||||
public IRequest(ServiceCtx context) { }
|
|
||||||
|
|
||||||
[CommandCmif(0)]
|
|
||||||
// InitializeOld(u32, u32, u32)
|
|
||||||
public ResultCode InitializeOld(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
|
|
||||||
int fgmId = context.RequestData.ReadInt32();
|
|
||||||
bool isAutoClearEvent = context.RequestData.ReadInt32() != 0;
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent });
|
|
||||||
|
|
||||||
Register(operationType, fgmId, isAutoClearEvent);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(1)]
|
|
||||||
// FinalizeOld(u32)
|
|
||||||
public ResultCode FinalizeOld(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
_sessionList.Remove(GetSessionByType(operationType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(2)]
|
|
||||||
// SetAndWaitOld(u32, u32, u32)
|
|
||||||
public ResultCode SetAndWaitOld(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
|
|
||||||
uint frequenceHz = context.RequestData.ReadUInt32();
|
|
||||||
int timeout = context.RequestData.ReadInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, frequenceHz, timeout });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
GetSessionByType(operationType)?.SetAndWait(frequenceHz, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(3)]
|
|
||||||
// GetOld(u32) -> u32
|
|
||||||
public ResultCode GetOld(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
MultiMediaSession session = GetSessionByType(operationType);
|
|
||||||
|
|
||||||
uint currentValue = session == null ? 0 : session.CurrentValue;
|
|
||||||
|
|
||||||
context.ResponseData.Write(currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(4)]
|
|
||||||
// Initialize(u32, u32, u32) -> u32
|
|
||||||
public ResultCode Initialize(ServiceCtx context)
|
|
||||||
{
|
|
||||||
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
|
|
||||||
int fgmId = context.RequestData.ReadInt32();
|
|
||||||
bool isAutoClearEvent = context.RequestData.ReadInt32() != 0;
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent });
|
|
||||||
|
|
||||||
uint id = Register(operationType, fgmId, isAutoClearEvent);
|
|
||||||
|
|
||||||
context.ResponseData.Write(id);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(5)]
|
|
||||||
// Finalize(u32)
|
|
||||||
public ResultCode Finalize(ServiceCtx context)
|
|
||||||
{
|
|
||||||
uint id = context.RequestData.ReadUInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
_sessionList.Remove(GetSessionById(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(6)]
|
|
||||||
// SetAndWait(u32, u32, u32)
|
|
||||||
public ResultCode SetAndWait(ServiceCtx context)
|
|
||||||
{
|
|
||||||
uint id = context.RequestData.ReadUInt32();
|
|
||||||
uint frequenceHz = context.RequestData.ReadUInt32();
|
|
||||||
int timeout = context.RequestData.ReadInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id, frequenceHz, timeout });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
GetSessionById(id)?.SetAndWait(frequenceHz, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CommandCmif(7)]
|
|
||||||
// Get(u32) -> u32
|
|
||||||
public ResultCode Get(ServiceCtx context)
|
|
||||||
{
|
|
||||||
uint id = context.RequestData.ReadUInt32();
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id });
|
|
||||||
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
MultiMediaSession session = GetSessionById(id);
|
|
||||||
|
|
||||||
uint currentValue = session == null ? 0 : session.CurrentValue;
|
|
||||||
|
|
||||||
context.ResponseData.Write(currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MultiMediaSession GetSessionById(uint id)
|
|
||||||
{
|
|
||||||
foreach (MultiMediaSession session in _sessionList)
|
|
||||||
{
|
|
||||||
if (session.Id == id)
|
|
||||||
{
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MultiMediaSession GetSessionByType(MultiMediaOperationType type)
|
|
||||||
{
|
|
||||||
foreach (MultiMediaSession session in _sessionList)
|
|
||||||
{
|
|
||||||
if (session.Type == type)
|
|
||||||
{
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint Register(MultiMediaOperationType type, int fgmId, bool isAutoClearEvent)
|
|
||||||
{
|
|
||||||
lock (_sessionListLock)
|
|
||||||
{
|
|
||||||
// Nintendo ignore the fgm id as the other interfaces were deprecated.
|
|
||||||
MultiMediaSession session = new(_uniqueId++, type, isAutoClearEvent);
|
|
||||||
|
|
||||||
_sessionList.Add(session);
|
|
||||||
|
|
||||||
return session.Id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Mm.Types
|
|
||||||
{
|
|
||||||
enum MultiMediaOperationType : uint
|
|
||||||
{
|
|
||||||
Ram = 2,
|
|
||||||
NvEnc = 5,
|
|
||||||
NvDec = 6,
|
|
||||||
NvJpg = 7,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Mm.Types
|
|
||||||
{
|
|
||||||
class MultiMediaSession
|
|
||||||
{
|
|
||||||
public MultiMediaOperationType Type { get; }
|
|
||||||
|
|
||||||
public bool IsAutoClearEvent { get; }
|
|
||||||
public uint Id { get; }
|
|
||||||
public uint CurrentValue { get; private set; }
|
|
||||||
|
|
||||||
public MultiMediaSession(uint id, MultiMediaOperationType type, bool isAutoClearEvent)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
Id = id;
|
|
||||||
IsAutoClearEvent = isAutoClearEvent;
|
|
||||||
CurrentValue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAndWait(uint value, int timeout)
|
|
||||||
{
|
|
||||||
CurrentValue = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
160
src/Ryujinx.Horizon/MmNv/Ipc/Request.cs
Normal file
160
src/Ryujinx.Horizon/MmNv/Ipc/Request.cs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.MmNv;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.MmNv.Ipc
|
||||||
|
{
|
||||||
|
partial class Request : IRequest
|
||||||
|
{
|
||||||
|
private readonly List<Session> _sessionList = new();
|
||||||
|
|
||||||
|
private uint _uniqueId = 1;
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent)
|
||||||
|
{
|
||||||
|
bool isAutoClearEvent = autoClearEvent != 0;
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent });
|
||||||
|
|
||||||
|
Register(module, fgmPriority, isAutoClearEvent);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(1)]
|
||||||
|
public Result FinalizeOld(Module module)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
_sessionList.Remove(GetSessionByModule(module));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(2)]
|
||||||
|
public Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, clockRateMin, clockRateMax });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
GetSessionByModule(module)?.SetAndWait(clockRateMin, clockRateMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(3)]
|
||||||
|
public Result GetOld(out uint clockRateActual, Module module)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
Session session = GetSessionByModule(module);
|
||||||
|
|
||||||
|
clockRateActual = session == null ? 0 : session.ClockRateMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(4)]
|
||||||
|
public Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent)
|
||||||
|
{
|
||||||
|
bool isAutoClearEvent = autoClearEvent != 0;
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent });
|
||||||
|
|
||||||
|
requestId = Register(module, fgmPriority, isAutoClearEvent);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(5)]
|
||||||
|
public Result Finalize(uint requestId)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
_sessionList.Remove(GetSessionById(requestId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(6)]
|
||||||
|
public Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId, clockRateMin, clockRateMax });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
GetSessionById(requestId)?.SetAndWait(clockRateMin, clockRateMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(7)]
|
||||||
|
public Result Get(out uint clockRateActual, uint requestId)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId });
|
||||||
|
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
Session session = GetSessionById(requestId);
|
||||||
|
|
||||||
|
clockRateActual = session == null ? 0 : session.ClockRateMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Session GetSessionById(uint id)
|
||||||
|
{
|
||||||
|
foreach (Session session in _sessionList)
|
||||||
|
{
|
||||||
|
if (session.Id == id)
|
||||||
|
{
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Session GetSessionByModule(Module module)
|
||||||
|
{
|
||||||
|
foreach (Session session in _sessionList)
|
||||||
|
{
|
||||||
|
if (session.Module == module)
|
||||||
|
{
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint Register(Module module, uint fgmPriority, bool isAutoClearEvent)
|
||||||
|
{
|
||||||
|
lock (_sessionList)
|
||||||
|
{
|
||||||
|
// Nintendo ignores the fgm priority as the other services were deprecated.
|
||||||
|
Session session = new(_uniqueId++, module, isAutoClearEvent);
|
||||||
|
|
||||||
|
_sessionList.Add(session);
|
||||||
|
|
||||||
|
return session.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs
Normal file
43
src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using Ryujinx.Horizon.MmNv.Ipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.MmNv
|
||||||
|
{
|
||||||
|
class MmNvIpcServer
|
||||||
|
{
|
||||||
|
private const int MmNvMaxSessionsCount = 9;
|
||||||
|
|
||||||
|
private const int PointerBufferSize = 0;
|
||||||
|
private const int MaxDomains = 0;
|
||||||
|
private const int MaxDomainObjects = 0;
|
||||||
|
private const int MaxPortsCount = 1;
|
||||||
|
|
||||||
|
private static readonly ManagerOptions _mmNvOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
|
||||||
|
|
||||||
|
private SmApi _sm;
|
||||||
|
private ServerManager _serverManager;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
HeapAllocator allocator = new();
|
||||||
|
|
||||||
|
_sm = new SmApi();
|
||||||
|
_sm.Initialize().AbortOnFailure();
|
||||||
|
|
||||||
|
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _mmNvOptions, MmNvMaxSessionsCount);
|
||||||
|
|
||||||
|
_serverManager.RegisterObjectForServer(new Request(), ServiceName.Encode("mm:u"), MmNvMaxSessionsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServiceRequests()
|
||||||
|
{
|
||||||
|
_serverManager.ServiceRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
_serverManager.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/Ryujinx.Horizon/MmNv/MmNvMain.cs
Normal file
17
src/Ryujinx.Horizon/MmNv/MmNvMain.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Ryujinx.Horizon.MmNv
|
||||||
|
{
|
||||||
|
class MmNvMain : IService
|
||||||
|
{
|
||||||
|
public static void Main(ServiceTable serviceTable)
|
||||||
|
{
|
||||||
|
MmNvIpcServer ipcServer = new();
|
||||||
|
|
||||||
|
ipcServer.Initialize();
|
||||||
|
|
||||||
|
serviceTable.SignalServiceReady();
|
||||||
|
|
||||||
|
ipcServer.ServiceRequests();
|
||||||
|
ipcServer.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs
Normal file
17
src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.MmNv
|
||||||
|
{
|
||||||
|
interface IRequest : IServiceObject
|
||||||
|
{
|
||||||
|
Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent);
|
||||||
|
Result FinalizeOld(Module module);
|
||||||
|
Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax);
|
||||||
|
Result GetOld(out uint clockRateActual, Module module);
|
||||||
|
Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent);
|
||||||
|
Result Finalize(uint requestId);
|
||||||
|
Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax);
|
||||||
|
Result Get(out uint clockRateActual, uint requestId);
|
||||||
|
}
|
||||||
|
}
|
15
src/Ryujinx.Horizon/Sdk/MmNv/Module.cs
Normal file
15
src/Ryujinx.Horizon/Sdk/MmNv/Module.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace Ryujinx.Horizon.Sdk.MmNv
|
||||||
|
{
|
||||||
|
enum Module : uint
|
||||||
|
{
|
||||||
|
Cpu,
|
||||||
|
Gpu,
|
||||||
|
Emc,
|
||||||
|
SysBus,
|
||||||
|
MSelect,
|
||||||
|
NvDec,
|
||||||
|
NvEnc,
|
||||||
|
NvJpg,
|
||||||
|
Test,
|
||||||
|
}
|
||||||
|
}
|
26
src/Ryujinx.Horizon/Sdk/MmNv/Session.cs
Normal file
26
src/Ryujinx.Horizon/Sdk/MmNv/Session.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
namespace Ryujinx.Horizon.Sdk.MmNv
|
||||||
|
{
|
||||||
|
class Session
|
||||||
|
{
|
||||||
|
public Module Module { get; }
|
||||||
|
public uint Id { get; }
|
||||||
|
public bool IsAutoClearEvent { get; }
|
||||||
|
public uint ClockRateMin { get; private set; }
|
||||||
|
public int ClockRateMax { get; private set; }
|
||||||
|
|
||||||
|
public Session(uint id, Module module, bool isAutoClearEvent)
|
||||||
|
{
|
||||||
|
Module = module;
|
||||||
|
Id = id;
|
||||||
|
IsAutoClearEvent = isAutoClearEvent;
|
||||||
|
ClockRateMin = 0;
|
||||||
|
ClockRateMax = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAndWait(uint clockRateMin, int clockRateMax)
|
||||||
|
{
|
||||||
|
ClockRateMin = clockRateMin;
|
||||||
|
ClockRateMax = clockRateMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Horizon.Bcat;
|
using Ryujinx.Horizon.Bcat;
|
||||||
using Ryujinx.Horizon.LogManager;
|
using Ryujinx.Horizon.LogManager;
|
||||||
|
using Ryujinx.Horizon.MmNv;
|
||||||
using Ryujinx.Horizon.Prepo;
|
using Ryujinx.Horizon.Prepo;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -25,6 +26,7 @@ namespace Ryujinx.Horizon
|
|||||||
RegisterService<LmMain>();
|
RegisterService<LmMain>();
|
||||||
RegisterService<PrepoMain>();
|
RegisterService<PrepoMain>();
|
||||||
RegisterService<BcatMain>();
|
RegisterService<BcatMain>();
|
||||||
|
RegisterService<MmNvMain>();
|
||||||
|
|
||||||
_totalServices = entries.Count;
|
_totalServices = entries.Count;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user