Move solution and projects to src

This commit is contained in:
TSR Berry
2023-04-08 01:22:00 +02:00
committed by Mary
parent cd124bda58
commit cee7121058
3466 changed files with 55 additions and 55 deletions

View File

@@ -0,0 +1,105 @@
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
{
class ILibraryAppletProxy : IpcService
{
private readonly ulong _pid;
public ILibraryAppletProxy(ulong pid)
{
_pid = pid;
}
[CommandCmif(0)]
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
public ResultCode GetCommonStateGetter(ServiceCtx context)
{
MakeObject(context, new ICommonStateGetter(context));
return ResultCode.Success;
}
[CommandCmif(1)]
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
MakeObject(context, new ISelfController(context, _pid));
return ResultCode.Success;
}
[CommandCmif(2)]
// GetWindowController() -> object<nn::am::service::IWindowController>
public ResultCode GetWindowController(ServiceCtx context)
{
MakeObject(context, new IWindowController(_pid));
return ResultCode.Success;
}
[CommandCmif(3)]
// GetAudioController() -> object<nn::am::service::IAudioController>
public ResultCode GetAudioController(ServiceCtx context)
{
MakeObject(context, new IAudioController());
return ResultCode.Success;
}
[CommandCmif(4)]
// GetDisplayController() -> object<nn::am::service::IDisplayController>
public ResultCode GetDisplayController(ServiceCtx context)
{
MakeObject(context, new IDisplayController(context));
return ResultCode.Success;
}
[CommandCmif(10)]
// GetProcessWindingController() -> object<nn::am::service::IProcessWindingController>
public ResultCode GetProcessWindingController(ServiceCtx context)
{
MakeObject(context, new IProcessWindingController());
return ResultCode.Success;
}
[CommandCmif(11)]
// GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
public ResultCode GetLibraryAppletCreator(ServiceCtx context)
{
MakeObject(context, new ILibraryAppletCreator());
return ResultCode.Success;
}
[CommandCmif(20)]
// OpenLibraryAppletSelfAccessor() -> object<nn::am::service::ILibraryAppletSelfAccessor>
public ResultCode OpenLibraryAppletSelfAccessor(ServiceCtx context)
{
MakeObject(context, new ILibraryAppletSelfAccessor(context));
return ResultCode.Success;
}
[CommandCmif(21)]
// GetAppletCommonFunctions() -> object<nn::am::service::IAppletCommonFunctions>
public ResultCode GetAppletCommonFunctions(ServiceCtx context)
{
MakeObject(context, new IAppletCommonFunctions());
return ResultCode.Success;
}
[CommandCmif(1000)]
// GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
public ResultCode GetDebugFunctions(ServiceCtx context)
{
MakeObject(context, new IDebugFunctions());
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,104 @@
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
{
class ISystemAppletProxy : IpcService
{
private readonly ulong _pid;
public ISystemAppletProxy(ulong pid)
{
_pid = pid;
}
[CommandCmif(0)]
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
public ResultCode GetCommonStateGetter(ServiceCtx context)
{
MakeObject(context, new ICommonStateGetter(context));
return ResultCode.Success;
}
[CommandCmif(1)]
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
MakeObject(context, new ISelfController(context, _pid));
return ResultCode.Success;
}
[CommandCmif(2)]
// GetWindowController() -> object<nn::am::service::IWindowController>
public ResultCode GetWindowController(ServiceCtx context)
{
MakeObject(context, new IWindowController(_pid));
return ResultCode.Success;
}
[CommandCmif(3)]
// GetAudioController() -> object<nn::am::service::IAudioController>
public ResultCode GetAudioController(ServiceCtx context)
{
MakeObject(context, new IAudioController());
return ResultCode.Success;
}
[CommandCmif(4)]
// GetDisplayController() -> object<nn::am::service::IDisplayController>
public ResultCode GetDisplayController(ServiceCtx context)
{
MakeObject(context, new IDisplayController(context));
return ResultCode.Success;
}
[CommandCmif(11)]
// GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
public ResultCode GetLibraryAppletCreator(ServiceCtx context)
{
MakeObject(context, new ILibraryAppletCreator());
return ResultCode.Success;
}
[CommandCmif(20)]
// GetHomeMenuFunctions() -> object<nn::am::service::IHomeMenuFunctions>
public ResultCode GetHomeMenuFunctions(ServiceCtx context)
{
MakeObject(context, new IHomeMenuFunctions(context.Device.System));
return ResultCode.Success;
}
[CommandCmif(21)]
// GetGlobalStateController() -> object<nn::am::service::IGlobalStateController>
public ResultCode GetGlobalStateController(ServiceCtx context)
{
MakeObject(context, new IGlobalStateController());
return ResultCode.Success;
}
[CommandCmif(22)]
// GetApplicationCreator() -> object<nn::am::service::IApplicationCreator>
public ResultCode GetApplicationCreator(ServiceCtx context)
{
MakeObject(context, new IApplicationCreator());
return ResultCode.Success;
}
[CommandCmif(1000)]
// GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
public ResultCode GetDebugFunctions(ServiceCtx context)
{
MakeObject(context, new IDebugFunctions());
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,261 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
{
class ILibraryAppletAccessor : DisposableIpcService
{
private KernelContext _kernelContext;
private IApplet _applet;
private AppletSession _normalSession;
private AppletSession _interactiveSession;
private KEvent _stateChangedEvent;
private KEvent _normalOutDataEvent;
private KEvent _interactiveOutDataEvent;
private int _stateChangedEventHandle;
private int _normalOutDataEventHandle;
private int _interactiveOutDataEventHandle;
private int _indirectLayerHandle;
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
{
_kernelContext = system.KernelContext;
_stateChangedEvent = new KEvent(system.KernelContext);
_normalOutDataEvent = new KEvent(system.KernelContext);
_interactiveOutDataEvent = new KEvent(system.KernelContext);
_applet = AppletManager.Create(appletId, system);
_normalSession = new AppletSession();
_interactiveSession = new AppletSession();
_applet.AppletStateChanged += OnAppletStateChanged;
_normalSession.DataAvailable += OnNormalOutData;
_interactiveSession.DataAvailable += OnInteractiveOutData;
Logger.Info?.Print(LogClass.ServiceAm, $"Applet '{appletId}' created.");
}
private void OnAppletStateChanged(object sender, EventArgs e)
{
_stateChangedEvent.WritableEvent.Signal();
}
private void OnNormalOutData(object sender, EventArgs e)
{
_normalOutDataEvent.WritableEvent.Signal();
}
private void OnInteractiveOutData(object sender, EventArgs e)
{
_interactiveOutDataEvent.WritableEvent.Signal();
}
[CommandCmif(0)]
// GetAppletStateChangedEvent() -> handle<copy>
public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
{
if (_stateChangedEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangedEventHandle);
return ResultCode.Success;
}
[CommandCmif(10)]
// Start()
public ResultCode Start(ServiceCtx context)
{
return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
}
[CommandCmif(20)]
// RequestExit()
public ResultCode RequestExit(ServiceCtx context)
{
// TODO: Since we don't support software Applet for now, we can just signals the changed state of the applet.
_stateChangedEvent.ReadableEvent.Signal();
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(30)]
// GetResult()
public ResultCode GetResult(ServiceCtx context)
{
return (ResultCode)_applet.GetResult();
}
[CommandCmif(60)]
// PresetLibraryAppletGpuTimeSliceZero()
public ResultCode PresetLibraryAppletGpuTimeSliceZero(ServiceCtx context)
{
// NOTE: This call reset two internal fields to 0 and one internal field to "true".
// It seems to be used only with software keyboard inline.
// Since we doesn't support applets for now, it's fine to stub it.
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(100)]
// PushInData(object<nn::am::service::IStorage>)
public ResultCode PushInData(ServiceCtx context)
{
IStorage data = GetObject<IStorage>(context, 0);
_normalSession.Push(data.Data);
return ResultCode.Success;
}
[CommandCmif(101)]
// PopOutData() -> object<nn::am::service::IStorage>
public ResultCode PopOutData(ServiceCtx context)
{
if (_normalSession.TryPop(out byte[] data))
{
MakeObject(context, new IStorage(data));
_normalOutDataEvent.WritableEvent.Clear();
return ResultCode.Success;
}
return ResultCode.NotAvailable;
}
[CommandCmif(103)]
// PushInteractiveInData(object<nn::am::service::IStorage>)
public ResultCode PushInteractiveInData(ServiceCtx context)
{
IStorage data = GetObject<IStorage>(context, 0);
_interactiveSession.Push(data.Data);
return ResultCode.Success;
}
[CommandCmif(104)]
// PopInteractiveOutData() -> object<nn::am::service::IStorage>
public ResultCode PopInteractiveOutData(ServiceCtx context)
{
if (_interactiveSession.TryPop(out byte[] data))
{
MakeObject(context, new IStorage(data));
_interactiveOutDataEvent.WritableEvent.Clear();
return ResultCode.Success;
}
return ResultCode.NotAvailable;
}
[CommandCmif(105)]
// GetPopOutDataEvent() -> handle<copy>
public ResultCode GetPopOutDataEvent(ServiceCtx context)
{
if (_normalOutDataEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_normalOutDataEventHandle);
return ResultCode.Success;
}
[CommandCmif(106)]
// GetPopInteractiveOutDataEvent() -> handle<copy>
public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
{
if (_interactiveOutDataEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_interactiveOutDataEventHandle);
return ResultCode.Success;
}
[CommandCmif(110)]
// NeedsToExitProcess()
public ResultCode NeedsToExitProcess(ServiceCtx context)
{
return ResultCode.Stubbed;
}
[CommandCmif(150)]
// RequestForAppletToGetForeground()
public ResultCode RequestForAppletToGetForeground(ServiceCtx context)
{
return ResultCode.Stubbed;
}
[CommandCmif(160)] // 2.0.0+
// GetIndirectLayerConsumerHandle() -> u64 indirect_layer_consumer_handle
public ResultCode GetIndirectLayerConsumerHandle(ServiceCtx context)
{
Horizon horizon = _kernelContext.Device.System;
_indirectLayerHandle = horizon.AppletState.IndirectLayerHandles.Add(_applet);
context.ResponseData.Write((ulong)_indirectLayerHandle);
return ResultCode.Success;
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
if (_stateChangedEventHandle != 0)
{
_kernelContext.Syscall.CloseHandle(_stateChangedEventHandle);
}
if (_normalOutDataEventHandle != 0)
{
_kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle);
}
if (_interactiveOutDataEventHandle != 0)
{
_kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle);
}
}
Horizon horizon = _kernelContext.Device.System;
horizon.AppletState.IndirectLayerHandles.Delete(_indirectLayerHandle);
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
{
class AppletStandalone
{
public AppletId AppletId;
public LibraryAppletMode LibraryAppletMode;
public Queue<byte[]> InputData;
public AppletStandalone()
{
InputData = new Queue<byte[]>();
}
}
}

View File

@@ -0,0 +1,78 @@
using Ryujinx.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
{
class ILibraryAppletSelfAccessor : IpcService
{
private AppletStandalone _appletStandalone = new AppletStandalone();
public ILibraryAppletSelfAccessor(ServiceCtx context)
{
if (context.Device.Processes.ActiveApplication.ProgramId == 0x0100000000001009)
{
// Create MiiEdit data.
_appletStandalone = new AppletStandalone()
{
AppletId = AppletId.MiiEdit,
LibraryAppletMode = LibraryAppletMode.AllForeground
};
byte[] miiEditInputData = new byte[0x100];
miiEditInputData[0] = 0x03; // Hardcoded unknown value.
_appletStandalone.InputData.Enqueue(miiEditInputData);
}
else
{
throw new NotImplementedException($"{context.Device.Processes.ActiveApplication.ProgramId} applet is not implemented.");
}
}
[CommandCmif(0)]
// PopInData() -> object<nn::am::service::IStorage>
public ResultCode PopInData(ServiceCtx context)
{
byte[] appletData = _appletStandalone.InputData.Dequeue();
if (appletData.Length == 0)
{
return ResultCode.NotAvailable;
}
MakeObject(context, new IStorage(appletData));
return ResultCode.Success;
}
[CommandCmif(11)]
// GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo
public ResultCode GetLibraryAppletInfo(ServiceCtx context)
{
LibraryAppletInfo libraryAppletInfo = new LibraryAppletInfo()
{
AppletId = _appletStandalone.AppletId,
LibraryAppletMode = _appletStandalone.LibraryAppletMode
};
context.ResponseData.WriteStruct(libraryAppletInfo);
return ResultCode.Success;
}
[CommandCmif(14)]
// GetCallerAppletIdentityInfo() -> nn::am::service::AppletIdentityInfo
public ResultCode GetCallerAppletIdentityInfo(ServiceCtx context)
{
AppletIdentifyInfo appletIdentifyInfo = new AppletIdentifyInfo()
{
AppletId = AppletId.QLaunch,
TitleId = 0x0100000000001000
};
context.ResponseData.WriteStruct(appletIdentifyInfo);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,24 @@
using Ryujinx.Common;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
{
class IProcessWindingController : IpcService
{
public IProcessWindingController() { }
[CommandCmif(0)]
// GetLaunchReason() -> nn::am::service::AppletProcessLaunchReason
public ResultCode GetLaunchReason(ServiceCtx context)
{
// NOTE: Flag is set by using an internal field.
AppletProcessLaunchReason appletProcessLaunchReason = new AppletProcessLaunchReason()
{
Flag = 0
};
context.ResponseData.WriteStruct(appletProcessLaunchReason);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IAppletCommonFunctions : IpcService
{
public IAppletCommonFunctions() { }
}
}

View File

@@ -0,0 +1,7 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IApplicationCreator : IpcService
{
public IApplicationCreator() { }
}
}

View File

@@ -0,0 +1,66 @@
using Ryujinx.Common.Logging;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IAudioController : IpcService
{
public IAudioController() { }
[CommandCmif(0)]
// SetExpectedMasterVolume(f32, f32)
public ResultCode SetExpectedMasterVolume(ServiceCtx context)
{
float appletVolume = context.RequestData.ReadSingle();
float libraryAppletVolume = context.RequestData.ReadSingle();
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(1)]
// GetMainAppletExpectedMasterVolume() -> f32
public ResultCode GetMainAppletExpectedMasterVolume(ServiceCtx context)
{
context.ResponseData.Write(1f);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(2)]
// GetLibraryAppletExpectedMasterVolume() -> f32
public ResultCode GetLibraryAppletExpectedMasterVolume(ServiceCtx context)
{
context.ResponseData.Write(1f);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(3)]
// ChangeMainAppletMasterVolume(f32, u64)
public ResultCode ChangeMainAppletMasterVolume(ServiceCtx context)
{
float unknown0 = context.RequestData.ReadSingle();
long unknown1 = context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(4)]
// SetTransparentVolumeRate(f32)
public ResultCode SetTransparentVolumeRate(ServiceCtx context)
{
float unknown0 = context.RequestData.ReadSingle();
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,285 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Settings.Types;
using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class ICommonStateGetter : IpcService
{
private Apm.ManagerServer _apmManagerServer;
private Apm.SystemManagerServer _apmSystemManagerServer;
private Lbl.LblControllerServer _lblControllerServer;
private bool _vrModeEnabled;
#pragma warning disable CS0414
private bool _lcdBacklighOffEnabled;
private bool _requestExitToLibraryAppletAtExecuteNextProgramEnabled;
#pragma warning restore CS0414
private int _messageEventHandle;
private int _displayResolutionChangedEventHandle;
public ICommonStateGetter(ServiceCtx context)
{
_apmManagerServer = new Apm.ManagerServer(context);
_apmSystemManagerServer = new Apm.SystemManagerServer(context);
_lblControllerServer = new Lbl.LblControllerServer(context);
}
[CommandCmif(0)]
// GetEventHandle() -> handle<copy>
public ResultCode GetEventHandle(ServiceCtx context)
{
KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
if (_messageEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_messageEventHandle);
return ResultCode.Success;
}
[CommandCmif(1)]
// ReceiveMessage() -> nn::am::AppletMessage
public ResultCode ReceiveMessage(ServiceCtx context)
{
if (!context.Device.System.AppletState.Messages.TryDequeue(out AppletMessage message))
{
return ResultCode.NoMessages;
}
KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
// NOTE: Service checks if current states are different than the stored ones.
// Since we don't support any states for now, it's fine to check if there is still messages available.
if (context.Device.System.AppletState.Messages.IsEmpty)
{
messageEvent.ReadableEvent.Clear();
}
else
{
messageEvent.ReadableEvent.Signal();
}
context.ResponseData.Write((int)message);
return ResultCode.Success;
}
[CommandCmif(5)]
// GetOperationMode() -> u8
public ResultCode GetOperationMode(ServiceCtx context)
{
OperationMode mode = context.Device.System.State.DockedMode
? OperationMode.Docked
: OperationMode.Handheld;
context.ResponseData.Write((byte)mode);
return ResultCode.Success;
}
[CommandCmif(6)]
// GetPerformanceMode() -> nn::apm::PerformanceMode
public ResultCode GetPerformanceMode(ServiceCtx context)
{
return (ResultCode)_apmManagerServer.GetPerformanceMode(context);
}
[CommandCmif(8)]
// GetBootMode() -> u8
public ResultCode GetBootMode(ServiceCtx context)
{
context.ResponseData.Write((byte)0); //Unknown value.
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(9)]
// GetCurrentFocusState() -> u8
public ResultCode GetCurrentFocusState(ServiceCtx context)
{
context.ResponseData.Write((byte)context.Device.System.AppletState.FocusState);
return ResultCode.Success;
}
[CommandCmif(50)] // 3.0.0+
// IsVrModeEnabled() -> b8
public ResultCode IsVrModeEnabled(ServiceCtx context)
{
context.ResponseData.Write(_vrModeEnabled);
return ResultCode.Success;
}
[CommandCmif(51)] // 3.0.0+
// SetVrModeEnabled(b8)
public ResultCode SetVrModeEnabled(ServiceCtx context)
{
bool vrModeEnabled = context.RequestData.ReadBoolean();
UpdateVrMode(vrModeEnabled);
return ResultCode.Success;
}
[CommandCmif(52)] // 4.0.0+
// SetLcdBacklighOffEnabled(b8)
public ResultCode SetLcdBacklighOffEnabled(ServiceCtx context)
{
// NOTE: Service sets a private field here, maybe this field is used somewhere else to turned off the backlight.
// Since we don't support backlight, it's fine to do nothing.
_lcdBacklighOffEnabled = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(53)] // 7.0.0+
// BeginVrModeEx()
public ResultCode BeginVrModeEx(ServiceCtx context)
{
UpdateVrMode(true);
return ResultCode.Success;
}
[CommandCmif(54)] // 7.0.0+
// EndVrModeEx()
public ResultCode EndVrModeEx(ServiceCtx context)
{
UpdateVrMode(false);
return ResultCode.Success;
}
private void UpdateVrMode(bool vrModeEnabled)
{
if (_vrModeEnabled == vrModeEnabled)
{
return;
}
_vrModeEnabled = vrModeEnabled;
if (vrModeEnabled)
{
_lblControllerServer.EnableVrMode();
}
else
{
_lblControllerServer.DisableVrMode();
}
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
}
[CommandCmif(60)] // 3.0.0+
// GetDefaultDisplayResolution() -> (u32, u32)
public ResultCode GetDefaultDisplayResolution(ServiceCtx context)
{
// NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolution of omm service.
// IOperationModeManager::GetDefaultDisplayResolution of omm service call IManagerDisplayService::GetDisplayResolution of vi service.
(ulong width, ulong height) = AndroidSurfaceComposerClient.GetDisplayInfo(context);
context.ResponseData.Write((uint)width);
context.ResponseData.Write((uint)height);
return ResultCode.Success;
}
[CommandCmif(61)] // 3.0.0+
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
{
// NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolutionChangeEvent of omm service.
if (_displayResolutionChangedEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_displayResolutionChangedEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(62)] // 4.0.0+
// GetHdcpAuthenticationState() -> s32 state
public ResultCode GetHdcpAuthenticationState(ServiceCtx context)
{
context.ResponseData.Write(0);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(66)] // 6.0.0+
// SetCpuBoostMode(u32 cpu_boost_mode)
public ResultCode SetCpuBoostMode(ServiceCtx context)
{
uint cpuBoostMode = context.RequestData.ReadUInt32();
if (cpuBoostMode > 1)
{
return ResultCode.InvalidParameters;
}
_apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode);
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
return ResultCode.Success;
}
[CommandCmif(91)] // 7.0.0+
// GetCurrentPerformanceConfiguration() -> nn::apm::PerformanceConfiguration
public ResultCode GetCurrentPerformanceConfiguration(ServiceCtx context)
{
return (ResultCode)_apmSystemManagerServer.GetCurrentPerformanceConfiguration(context);
}
[CommandCmif(300)] // 9.0.0+
// GetSettingsPlatformRegion() -> u8
public ResultCode GetSettingsPlatformRegion(ServiceCtx context)
{
PlatformRegion platformRegion = context.Device.System.State.DesiredRegionCode == (uint)RegionCode.China ? PlatformRegion.China : PlatformRegion.Global;
// FIXME: Call set:sys GetPlatformRegion
context.ResponseData.Write((byte)platformRegion);
return ResultCode.Success;
}
[CommandCmif(900)] // 11.0.0+
// SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled()
public ResultCode SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(ServiceCtx context)
{
// TODO : Find where the field is used.
_requestExitToLibraryAppletAtExecuteNextProgramEnabled = true;
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IDebugFunctions : IpcService
{
public IDebugFunctions() { }
}
}

View File

@@ -0,0 +1,106 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IDisplayController : IpcService
{
private KTransferMemory _transferMem;
private bool _lastApplicationCaptureBufferAcquired;
private bool _callerAppletCaptureBufferAcquired;
public IDisplayController(ServiceCtx context)
{
_transferMem = context.Device.System.AppletCaptureBufferTransfer;
}
[CommandCmif(8)] // 2.0.0+
// TakeScreenShotOfOwnLayer(b8, s32)
public ResultCode TakeScreenShotOfOwnLayer(ServiceCtx context)
{
bool unknown1 = context.RequestData.ReadBoolean();
int unknown2 = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { unknown1, unknown2 });
return ResultCode.Success;
}
[CommandCmif(11)]
// ReleaseLastApplicationCaptureBuffer()
public ResultCode ReleaseLastApplicationCaptureBuffer(ServiceCtx context)
{
if (!_lastApplicationCaptureBufferAcquired)
{
return ResultCode.BufferNotAcquired;
}
_lastApplicationCaptureBufferAcquired = false;
return ResultCode.Success;
}
[CommandCmif(15)]
// ReleaseCallerAppletCaptureBuffer()
public ResultCode ReleaseCallerAppletCaptureBuffer(ServiceCtx context)
{
if (!_callerAppletCaptureBufferAcquired)
{
return ResultCode.BufferNotAcquired;
}
_callerAppletCaptureBufferAcquired = false;
return ResultCode.Success;
}
[CommandCmif(16)]
// AcquireLastApplicationCaptureBufferEx() -> (b8, handle<copy>)
public ResultCode AcquireLastApplicationCaptureBufferEx(ServiceCtx context)
{
if (_lastApplicationCaptureBufferAcquired)
{
return ResultCode.BufferAlreadyAcquired;
}
if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
_lastApplicationCaptureBufferAcquired = true;
context.ResponseData.Write(_lastApplicationCaptureBufferAcquired);
return ResultCode.Success;
}
[CommandCmif(18)]
// AcquireCallerAppletCaptureBufferEx() -> (b8, handle<copy>)
public ResultCode AcquireCallerAppletCaptureBufferEx(ServiceCtx context)
{
if (_callerAppletCaptureBufferAcquired)
{
return ResultCode.BufferAlreadyAcquired;
}
if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
_callerAppletCaptureBufferAcquired = true;
context.ResponseData.Write(_callerAppletCaptureBufferAcquired);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IGlobalStateController : IpcService
{
public IGlobalStateController() { }
}
}

View File

@@ -0,0 +1,48 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IHomeMenuFunctions : IpcService
{
private KEvent _channelEvent;
private int _channelEventHandle;
public IHomeMenuFunctions(Horizon system)
{
// TODO: Signal this Event somewhere in future.
_channelEvent = new KEvent(system.KernelContext);
}
[CommandCmif(10)]
// RequestToGetForeground()
public ResultCode RequestToGetForeground(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(21)]
// GetPopFromGeneralChannelEvent() -> handle<copy>
public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context)
{
if (_channelEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_channelEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,91 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class ILibraryAppletCreator : IpcService
{
public ILibraryAppletCreator() { }
[CommandCmif(0)]
// CreateLibraryApplet(u32, u32) -> object<nn::am::service::ILibraryAppletAccessor>
public ResultCode CreateLibraryApplet(ServiceCtx context)
{
AppletId appletId = (AppletId)context.RequestData.ReadInt32();
int libraryAppletMode = context.RequestData.ReadInt32();
MakeObject(context, new ILibraryAppletAccessor(appletId, context.Device.System));
return ResultCode.Success;
}
[CommandCmif(10)]
// CreateStorage(u64) -> object<nn::am::service::IStorage>
public ResultCode CreateStorage(ServiceCtx context)
{
long size = context.RequestData.ReadInt64();
if (size <= 0)
{
return ResultCode.ObjectInvalid;
}
MakeObject(context, new IStorage(new byte[size]));
// NOTE: Returns ResultCode.MemoryAllocationFailed if IStorage is null, it doesn't occur in our case.
return ResultCode.Success;
}
[CommandCmif(11)]
// CreateTransferMemoryStorage(b8, u64, handle<copy>) -> object<nn::am::service::IStorage>
public ResultCode CreateTransferMemoryStorage(ServiceCtx context)
{
bool isReadOnly = (context.RequestData.ReadInt64() & 1) == 0;
long size = context.RequestData.ReadInt64();
int handle = context.Request.HandleDesc.ToCopy[0];
KTransferMemory transferMem = context.Process.HandleTable.GetObject<KTransferMemory>(handle);
if (size <= 0)
{
return ResultCode.ObjectInvalid;
}
byte[] data = new byte[transferMem.Size];
transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
context.Device.System.KernelContext.Syscall.CloseHandle(handle);
MakeObject(context, new IStorage(data, isReadOnly));
return ResultCode.Success;
}
[CommandCmif(12)] // 2.0.0+
// CreateHandleStorage(u64, handle<copy>) -> object<nn::am::service::IStorage>
public ResultCode CreateHandleStorage(ServiceCtx context)
{
long size = context.RequestData.ReadInt64();
int handle = context.Request.HandleDesc.ToCopy[0];
KTransferMemory transferMem = context.Process.HandleTable.GetObject<KTransferMemory>(handle);
if (size <= 0)
{
return ResultCode.ObjectInvalid;
}
byte[] data = new byte[transferMem.Size];
transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
context.Device.System.KernelContext.Syscall.CloseHandle(handle);
MakeObject(context, new IStorage(data));
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,432 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy.Types;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class ISelfController : IpcService
{
private readonly ulong _pid;
private KEvent _libraryAppletLaunchableEvent;
private int _libraryAppletLaunchableEventHandle;
private KEvent _accumulatedSuspendedTickChangedEvent;
private int _accumulatedSuspendedTickChangedEventHandle;
private object _fatalSectionLock = new object();
private int _fatalSectionCount;
// TODO: Set this when the game goes in suspension (go back to home menu ect), we currently don't support that so we can keep it set to 0.
private ulong _accumulatedSuspendedTickValue = 0;
// TODO: Determine where those fields are used.
private bool _screenShotPermission = false;
private bool _operationModeChangedNotification = false;
private bool _performanceModeChangedNotification = false;
private bool _restartMessageEnabled = false;
private bool _outOfFocusSuspendingEnabled = false;
private bool _handlesRequestToDisplay = false;
private bool _autoSleepDisabled = false;
private bool _albumImageTakenNotificationEnabled = false;
private bool _recordVolumeMuted = false;
private uint _screenShotImageOrientation = 0;
private uint _idleTimeDetectionExtension = 0;
public ISelfController(ServiceCtx context, ulong pid)
{
_libraryAppletLaunchableEvent = new KEvent(context.Device.System.KernelContext);
_pid = pid;
}
[CommandCmif(0)]
// Exit()
public ResultCode Exit(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(1)]
// LockExit()
public ResultCode LockExit(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(2)]
// UnlockExit()
public ResultCode UnlockExit(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(3)] // 2.0.0+
// EnterFatalSection()
public ResultCode EnterFatalSection(ServiceCtx context)
{
lock (_fatalSectionLock)
{
_fatalSectionCount++;
}
return ResultCode.Success;
}
[CommandCmif(4)] // 2.0.0+
// LeaveFatalSection()
public ResultCode LeaveFatalSection(ServiceCtx context)
{
ResultCode result = ResultCode.Success;
lock (_fatalSectionLock)
{
if (_fatalSectionCount != 0)
{
_fatalSectionCount--;
}
else
{
result = ResultCode.UnbalancedFatalSection;
}
}
return result;
}
[CommandCmif(9)]
// GetLibraryAppletLaunchableEvent() -> handle<copy>
public ResultCode GetLibraryAppletLaunchableEvent(ServiceCtx context)
{
_libraryAppletLaunchableEvent.ReadableEvent.Signal();
if (_libraryAppletLaunchableEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_libraryAppletLaunchableEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(10)]
// SetScreenShotPermission(u32)
public ResultCode SetScreenShotPermission(ServiceCtx context)
{
bool screenShotPermission = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { screenShotPermission });
_screenShotPermission = screenShotPermission;
return ResultCode.Success;
}
[CommandCmif(11)]
// SetOperationModeChangedNotification(b8)
public ResultCode SetOperationModeChangedNotification(ServiceCtx context)
{
bool operationModeChangedNotification = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { operationModeChangedNotification });
_operationModeChangedNotification = operationModeChangedNotification;
return ResultCode.Success;
}
[CommandCmif(12)]
// SetPerformanceModeChangedNotification(b8)
public ResultCode SetPerformanceModeChangedNotification(ServiceCtx context)
{
bool performanceModeChangedNotification = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { performanceModeChangedNotification });
_performanceModeChangedNotification = performanceModeChangedNotification;
return ResultCode.Success;
}
[CommandCmif(13)]
// SetFocusHandlingMode(b8, b8, b8)
public ResultCode SetFocusHandlingMode(ServiceCtx context)
{
bool unknownFlag1 = context.RequestData.ReadBoolean();
bool unknownFlag2 = context.RequestData.ReadBoolean();
bool unknownFlag3 = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { unknownFlag1, unknownFlag2, unknownFlag3 });
return ResultCode.Success;
}
[CommandCmif(14)]
// SetRestartMessageEnabled(b8)
public ResultCode SetRestartMessageEnabled(ServiceCtx context)
{
bool restartMessageEnabled = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { restartMessageEnabled });
_restartMessageEnabled = restartMessageEnabled;
return ResultCode.Success;
}
[CommandCmif(16)] // 2.0.0+
// SetOutOfFocusSuspendingEnabled(b8)
public ResultCode SetOutOfFocusSuspendingEnabled(ServiceCtx context)
{
bool outOfFocusSuspendingEnabled = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { outOfFocusSuspendingEnabled });
_outOfFocusSuspendingEnabled = outOfFocusSuspendingEnabled;
return ResultCode.Success;
}
[CommandCmif(19)] // 3.0.0+
// SetScreenShotImageOrientation(u32)
public ResultCode SetScreenShotImageOrientation(ServiceCtx context)
{
uint screenShotImageOrientation = context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { screenShotImageOrientation });
_screenShotImageOrientation = screenShotImageOrientation;
return ResultCode.Success;
}
[CommandCmif(40)]
// CreateManagedDisplayLayer() -> u64
public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
{
context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, _pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
context.ResponseData.Write(layerId);
return ResultCode.Success;
}
[CommandCmif(41)] // 4.0.0+
// IsSystemBufferSharingEnabled()
public ResultCode IsSystemBufferSharingEnabled(ServiceCtx context)
{
// NOTE: Service checks a private field and return an error if the SystemBufferSharing is disabled.
return ResultCode.NotImplemented;
}
[CommandCmif(44)] // 10.0.0+
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
{
context.Device.System.SurfaceFlinger.CreateLayer(out long displayLayerId, _pid);
context.Device.System.SurfaceFlinger.CreateLayer(out long recordingLayerId, _pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId);
context.ResponseData.Write(displayLayerId);
context.ResponseData.Write(recordingLayerId);
return ResultCode.Success;
}
[CommandCmif(50)]
// SetHandlesRequestToDisplay(b8)
public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)
{
bool handlesRequestToDisplay = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { handlesRequestToDisplay });
_handlesRequestToDisplay = handlesRequestToDisplay;
return ResultCode.Success;
}
[CommandCmif(62)]
// SetIdleTimeDetectionExtension(u32)
public ResultCode SetIdleTimeDetectionExtension(ServiceCtx context)
{
uint idleTimeDetectionExtension = context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { idleTimeDetectionExtension });
_idleTimeDetectionExtension = idleTimeDetectionExtension;
return ResultCode.Success;
}
[CommandCmif(63)]
// GetIdleTimeDetectionExtension() -> u32
public ResultCode GetIdleTimeDetectionExtension(ServiceCtx context)
{
context.ResponseData.Write(_idleTimeDetectionExtension);
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { _idleTimeDetectionExtension });
return ResultCode.Success;
}
[CommandCmif(65)]
// ReportUserIsActive()
public ResultCode ReportUserIsActive(ServiceCtx context)
{
// TODO: Call idle:sys ReportUserIsActive when implemented.
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(67)] //3.0.0+
// IsIlluminanceAvailable() -> bool
public ResultCode IsIlluminanceAvailable(ServiceCtx context)
{
// NOTE: This should call IsAmbientLightSensorAvailable through to Lbl, but there's no situation where we'd want false.
context.ResponseData.Write(true);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(68)]
// SetAutoSleepDisabled(u8)
public ResultCode SetAutoSleepDisabled(ServiceCtx context)
{
bool autoSleepDisabled = context.RequestData.ReadBoolean();
_autoSleepDisabled = autoSleepDisabled;
return ResultCode.Success;
}
[CommandCmif(69)]
// IsAutoSleepDisabled() -> u8
public ResultCode IsAutoSleepDisabled(ServiceCtx context)
{
context.ResponseData.Write(_autoSleepDisabled);
return ResultCode.Success;
}
[CommandCmif(71)] //5.0.0+
// GetCurrentIlluminanceEx() -> (bool, f32)
public ResultCode GetCurrentIlluminanceEx(ServiceCtx context)
{
// TODO: The light value should be configurable - presumably users using software that takes advantage will want control.
context.ResponseData.Write(1); // OverLimit
context.ResponseData.Write(10000f); // Lux - 10K lux is ambient light.
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
[CommandCmif(80)] // 4.0.0+
// SetWirelessPriorityMode(s32 wireless_priority_mode)
public ResultCode SetWirelessPriorityMode(ServiceCtx context)
{
WirelessPriorityMode wirelessPriorityMode = (WirelessPriorityMode)context.RequestData.ReadInt32();
if (wirelessPriorityMode > WirelessPriorityMode.Unknown2)
{
return ResultCode.InvalidParameters;
}
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { wirelessPriorityMode });
return ResultCode.Success;
}
[CommandCmif(90)] // 6.0.0+
// GetAccumulatedSuspendedTickValue() -> u64
public ResultCode GetAccumulatedSuspendedTickValue(ServiceCtx context)
{
context.ResponseData.Write(_accumulatedSuspendedTickValue);
return ResultCode.Success;
}
[CommandCmif(91)] // 6.0.0+
// GetAccumulatedSuspendedTickChangedEvent() -> handle<copy>
public ResultCode GetAccumulatedSuspendedTickChangedEvent(ServiceCtx context)
{
if (_accumulatedSuspendedTickChangedEventHandle == 0)
{
_accumulatedSuspendedTickChangedEvent = new KEvent(context.Device.System.KernelContext);
_accumulatedSuspendedTickChangedEvent.ReadableEvent.Signal();
if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_accumulatedSuspendedTickChangedEventHandle);
return ResultCode.Success;
}
[CommandCmif(100)] // 7.0.0+
// SetAlbumImageTakenNotificationEnabled(u8)
public ResultCode SetAlbumImageTakenNotificationEnabled(ServiceCtx context)
{
bool albumImageTakenNotificationEnabled = context.RequestData.ReadBoolean();
_albumImageTakenNotificationEnabled = albumImageTakenNotificationEnabled;
return ResultCode.Success;
}
[CommandCmif(120)] // 11.0.0+
// SaveCurrentScreenshot(s32 album_report_option)
public ResultCode SaveCurrentScreenshot(ServiceCtx context)
{
AlbumReportOption albumReportOption = (AlbumReportOption)context.RequestData.ReadInt32();
if (albumReportOption > AlbumReportOption.Unknown3)
{
return ResultCode.InvalidParameters;
}
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { albumReportOption });
return ResultCode.Success;
}
[CommandCmif(130)] // 13.0.0+
// SetRecordVolumeMuted(b8)
public ResultCode SetRecordVolumeMuted(ServiceCtx context)
{
bool recordVolumeMuted = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { recordVolumeMuted });
_recordVolumeMuted = recordVolumeMuted;
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,36 @@
using Ryujinx.Common.Logging;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class IWindowController : IpcService
{
private readonly ulong _pid;
public IWindowController(ulong pid)
{
_pid = pid;
}
[CommandCmif(1)]
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
public ResultCode GetAppletResourceUserId(ServiceCtx context)
{
long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
context.ResponseData.Write(appletResourceUserId);
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { appletResourceUserId });
return ResultCode.Success;
}
[CommandCmif(10)]
// AcquireForegroundRights()
public ResultCode AcquireForegroundRights(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy.Types
{
enum AlbumReportOption
{
OverlayNotDisplayed,
OverlayDisplayed,
Unknown2,
Unknown3
}
}

View File

@@ -0,0 +1,36 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
enum AppletMessage
{
None = 0,
ChangeIntoForeground = 1,
ChangeIntoBackground = 2,
Exit = 4,
ApplicationExited = 6,
FocusStateChanged = 15,
Resume = 16,
DetectShortPressingHomeButton = 20,
DetectLongPressingHomeButton = 21,
DetectShortPressingPowerButton = 22,
DetectMiddlePressingPowerButton = 23,
DetectLongPressingPowerButton = 24,
RequestToPrepareSleep = 25,
FinishedSleepSequence = 26,
SleepRequiredByHighTemperature = 27,
SleepRequiredByLowBattery = 28,
AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
DetectReceivingCecSystemStandby = 32,
SdCardRemoved = 33,
LaunchApplicationRequested = 50,
RequestToDisplay = 51,
ShowApplicationLogo = 55,
HideApplicationLogo = 56,
ForceHideApplicationLogo = 57,
FloatingApplicationDetected = 60,
DetectShortPressingCaptureButton = 90,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93
}
}

View File

@@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
}

View File

@@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
enum OperationMode
{
Handheld = 0,
Docked = 1
}
}

View File

@@ -0,0 +1,9 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy.Types
{
enum WirelessPriorityMode
{
Default,
OptimizedForWlan,
Unknown2
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
internal class AppletFifo<T> : IAppletFifo<T>
{
private ConcurrentQueue<T> _dataQueue;
public event EventHandler DataAvailable;
public bool IsSynchronized
{
get { return ((ICollection)_dataQueue).IsSynchronized; }
}
public object SyncRoot
{
get { return ((ICollection)_dataQueue).SyncRoot; }
}
public int Count
{
get { return _dataQueue.Count; }
}
public AppletFifo()
{
_dataQueue = new ConcurrentQueue<T>();
}
public void Push(T item)
{
_dataQueue.Enqueue(item);
DataAvailable?.Invoke(this, null);
}
public bool TryAdd(T item)
{
try
{
this.Push(item);
return true;
}
catch
{
return false;
}
}
public T Pop()
{
if (_dataQueue.TryDequeue(out T result))
{
return result;
}
throw new InvalidOperationException("FIFO empty.");
}
public bool TryPop(out T result)
{
return _dataQueue.TryDequeue(out result);
}
public bool TryTake(out T item)
{
return this.TryPop(out item);
}
public T Peek()
{
if (_dataQueue.TryPeek(out T result))
{
return result;
}
throw new InvalidOperationException("FIFO empty.");
}
public bool TryPeek(out T result)
{
return _dataQueue.TryPeek(out result);
}
public void Clear()
{
_dataQueue.Clear();
}
public T[] ToArray()
{
return _dataQueue.ToArray();
}
public void CopyTo(T[] array, int arrayIndex)
{
_dataQueue.CopyTo(array, arrayIndex);
}
public void CopyTo(Array array, int index)
{
this.CopyTo((T[])array, index);
}
public IEnumerator<T> GetEnumerator()
{
return _dataQueue.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _dataQueue.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
internal class AppletSession
{
private IAppletFifo<byte[]> _inputData;
private IAppletFifo<byte[]> _outputData;
public event EventHandler DataAvailable;
public int Length
{
get { return _inputData.Count; }
}
public AppletSession()
: this(new AppletFifo<byte[]>(),
new AppletFifo<byte[]>())
{ }
public AppletSession(
IAppletFifo<byte[]> inputData,
IAppletFifo<byte[]> outputData)
{
_inputData = inputData;
_outputData = outputData;
_inputData.DataAvailable += OnDataAvailable;
}
private void OnDataAvailable(object sender, EventArgs e)
{
DataAvailable?.Invoke(this, null);
}
public void Push(byte[] item)
{
if (!this.TryPush(item))
{
// TODO(jduncanator): Throw a proper exception
throw new InvalidOperationException();
}
}
public bool TryPush(byte[] item)
{
return _outputData.TryAdd(item);
}
public byte[] Pop()
{
if (this.TryPop(out byte[] item))
{
return item;
}
throw new InvalidOperationException("Input data empty.");
}
public bool TryPop(out byte[] item)
{
return _inputData.TryTake(out item);
}
/// <summary>
/// This returns an AppletSession that can be used at the
/// other end of the pipe. Pushing data into this new session
/// will put it in the first session's input buffer, and vice
/// versa.
/// </summary>
public AppletSession GetConsumer()
{
return new AppletSession(this._outputData, this._inputData);
}
}
}

View File

@@ -0,0 +1,29 @@
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
[Service("appletAE")]
class IAllSystemAppletProxiesService : IpcService
{
public IAllSystemAppletProxiesService(ServiceCtx context) { }
[CommandCmif(100)]
// OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
public ResultCode OpenSystemAppletProxy(ServiceCtx context)
{
MakeObject(context, new ISystemAppletProxy(context.Request.HandleDesc.PId));
return ResultCode.Success;
}
[CommandCmif(200)]
[CommandCmif(201)] // 3.0.0+
// OpenLibraryAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ILibraryAppletProxy>
public ResultCode OpenLibraryAppletProxy(ServiceCtx context)
{
MakeObject(context, new ILibraryAppletProxy(context.Request.HandleDesc.PId));
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Concurrent;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
interface IAppletFifo<T> : IProducerConsumerCollection<T>
{
event EventHandler DataAvailable;
}
}

View File

@@ -0,0 +1,23 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
class IStorage : IpcService
{
public bool IsReadOnly { get; private set; }
public byte[] Data { get; private set; }
public IStorage(byte[] data, bool isReadOnly = false)
{
IsReadOnly = isReadOnly;
Data = data;
}
[CommandCmif(0)]
// Open() -> object<nn::am::service::IStorageAccessor>
public ResultCode Open(ServiceCtx context)
{
MakeObject(context, new IStorageAccessor(this));
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
class IStorageAccessor : IpcService
{
private IStorage _storage;
public IStorageAccessor(IStorage storage)
{
_storage = storage;
}
[CommandCmif(0)]
// GetSize() -> u64
public ResultCode GetSize(ServiceCtx context)
{
context.ResponseData.Write((long)_storage.Data.Length);
return ResultCode.Success;
}
[CommandCmif(10)]
// Write(u64, buffer<bytes, 0x21>)
public ResultCode Write(ServiceCtx context)
{
if (_storage.IsReadOnly)
{
return ResultCode.ObjectInvalid;
}
ulong writePosition = context.RequestData.ReadUInt64();
if (writePosition > (ulong)_storage.Data.Length)
{
return ResultCode.OutOfBounds;
}
(ulong position, ulong size) = context.Request.GetBufferType0x21();
size = Math.Min(size, (ulong)_storage.Data.Length - writePosition);
if (size > 0)
{
ulong maxSize = (ulong)_storage.Data.Length - writePosition;
if (size > maxSize)
{
size = maxSize;
}
byte[] data = new byte[size];
context.Memory.Read(position, data);
Buffer.BlockCopy(data, 0, _storage.Data, (int)writePosition, (int)size);
}
return ResultCode.Success;
}
[CommandCmif(11)]
// Read(u64) -> buffer<bytes, 0x22>
public ResultCode Read(ServiceCtx context)
{
ulong readPosition = context.RequestData.ReadUInt64();
if (readPosition > (ulong)_storage.Data.Length)
{
return ResultCode.OutOfBounds;
}
(ulong position, ulong size) = context.Request.GetBufferType0x22();
size = Math.Min(size, (ulong)_storage.Data.Length - readPosition);
byte[] data = new byte[size];
Buffer.BlockCopy(_storage.Data, (int)readPosition, data, 0, (int)size);
context.Memory.Write(position, data);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,28 @@
using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using System.IO;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage
{
class StorageHelper
{
private const uint LaunchParamsMagic = 0xc79497ca;
public static byte[] MakeLaunchParams(UserProfile userProfile)
{
// Size needs to be at least 0x88 bytes otherwise application errors.
using (MemoryStream ms = MemoryStreamManager.Shared.GetStream())
{
BinaryWriter writer = new BinaryWriter(ms);
ms.SetLength(0x88);
writer.Write(LaunchParamsMagic);
writer.Write(1); // IsAccountSelected? Only lower 8 bits actually used.
userProfile.UserId.Write(writer);
return ms.ToArray();
}
}
}
}

View File

@@ -0,0 +1,27 @@
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
enum AppletId
{
Application = 0x01,
OverlayDisplay = 0x02,
QLaunch = 0x03,
Starter = 0x04,
Auth = 0x0A,
Cabinet = 0x0B,
Controller = 0x0C,
DataErase = 0x0D,
Error = 0x0E,
NetConnect = 0x0F,
PlayerSelect = 0x10,
SoftwareKeyboard = 0x11,
MiiEdit = 0x12,
LibAppletWeb = 0x13,
LibAppletShop = 0x14,
PhotoViewer = 0x15,
Settings = 0x16,
LibAppletOff = 0x17,
LibAppletWhitelisted = 0x18,
LibAppletAuth = 0x19,
MyPage = 0x1A
}
}

View File

@@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
struct AppletIdentifyInfo
{
public AppletId AppletId;
public uint Padding;
public ulong TitleId;
}
}

View File

@@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
[StructLayout(LayoutKind.Sequential, Size = 0x4)]
struct AppletProcessLaunchReason
{
public byte Flag;
public ushort Unknown1;
public byte Unknown2;
}
}

View File

@@ -0,0 +1,11 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
[StructLayout(LayoutKind.Sequential, Size = 0x8)]
struct LibraryAppletInfo
{
public AppletId AppletId;
public LibraryAppletMode LibraryAppletMode;
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
{
[Flags]
enum LibraryAppletMode : uint
{
AllForeground,
PartialForeground,
NoUi,
PartialForegroundWithIndirectDisplay,
AllForegroundInitiallyHidden
}
}