From a0720b5681852f3d786d77bd3793b0359dea321c Mon Sep 17 00:00:00 2001 From: Ac_K Date: Thu, 19 Sep 2019 02:45:11 +0200 Subject: Refactoring HOS folder structure (#771) * Refactoring HOS folder structure Refactoring HOS folder structure: - Added some subfolders when needed (Following structure decided in private). - Added some `Types` folders when needed. - Little cleanup here and there. - Add services placeholders for every HOS services (close #766 and #753). * Remove Types namespaces --- Ryujinx.HLE/HOS/Horizon.cs | 3 +- .../HOS/Services/Acc/Account/AccountState.cs | 8 - .../HOS/Services/Acc/Account/AccountUtils.cs | 68 - .../HOS/Services/Acc/Account/UserProfile.cs | 37 - Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs | 298 ---- .../HOS/Services/Acc/IManagerForApplication.cs | 40 - Ryujinx.HLE/HOS/Services/Acc/IProfile.cs | 81 - Ryujinx.HLE/HOS/Services/Acc/ResultCode.cs | 20 - .../Account/Acc/AccountService/AccountUtils.cs | 67 + .../Account/Acc/IAccountServiceForAdministrator.cs | 8 + .../Account/Acc/IAccountServiceForApplication.cs | 294 ++++ .../Account/Acc/IAccountServiceForSystemService.cs | 8 + .../Account/Acc/IBaasAccessTokenAccessor.cs | 8 + .../Services/Account/Acc/IManagerForApplication.cs | 40 + Ryujinx.HLE/HOS/Services/Account/Acc/IProfile.cs | 80 + .../HOS/Services/Account/Acc/Types/AccountState.cs | 8 + .../HOS/Services/Account/Acc/Types/UserProfile.cs | 37 + Ryujinx.HLE/HOS/Services/Account/Dauth/IService.cs | 8 + Ryujinx.HLE/HOS/Services/Account/ResultCode.cs | 20 + .../ISystemAppletProxy.cs | 99 ++ .../LibraryAppletCreator/ILibraryAppletAccessor.cs | 73 + .../SystemAppletProxy/IApplicationCreator.cs | 7 + .../SystemAppletProxy/IAudioController.cs | 66 + .../SystemAppletProxy/ICommonStateGetter.cs | 142 ++ .../SystemAppletProxy/IDebugFunctions.cs | 7 + .../SystemAppletProxy/IDisplayController.cs | 7 + .../SystemAppletProxy/IGlobalStateController.cs | 7 + .../SystemAppletProxy/IHomeMenuFunctions.cs | 44 + .../SystemAppletProxy/ILibraryAppletCreator.cs | 29 + .../SystemAppletProxy/ISelfController.cs | 200 +++ .../SystemAppletProxy/IWindowController.cs | 29 + .../SystemAppletProxy/Types/FocusState.cs | 8 + .../SystemAppletProxy/Types/MessageInfo.cs | 9 + .../SystemAppletProxy/Types/OperationMode.cs | 8 + .../Am/AppletAE/IAllSystemAppletProxiesService.cs | 19 + Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs | 21 + .../HOS/Services/Am/AppletAE/IStorageAccessor.cs | 76 + .../Services/Am/AppletAE/Storage/StorageHelper.cs | 27 + .../ApplicationProxy/IApplicationFunctions.cs | 117 ++ .../ApplicationProxyService/IApplicationProxy.cs | 82 + .../Am/AppletOE/IApplicationProxyService.cs | 20 + Ryujinx.HLE/HOS/Services/Am/FocusState.cs | 8 - .../Services/Am/IAllSystemAppletProxiesService.cs | 17 - Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs | 7 - .../HOS/Services/Am/IApplicationFunctions.cs | 115 -- Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs | 79 - .../HOS/Services/Am/IApplicationProxyService.cs | 17 - Ryujinx.HLE/HOS/Services/Am/IAudioController.cs | 66 - Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs | 141 -- Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs | 7 - Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs | 7 - .../HOS/Services/Am/IGlobalStateController.cs | 7 - Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs | 44 - .../HOS/Services/Am/ILibraryAppletAccessor.cs | 72 - .../HOS/Services/Am/ILibraryAppletCreator.cs | 27 - Ryujinx.HLE/HOS/Services/Am/ISelfController.cs | 200 --- Ryujinx.HLE/HOS/Services/Am/IStorage.cs | 21 - Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs | 76 - Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs | 97 -- Ryujinx.HLE/HOS/Services/Am/IWindowController.cs | 29 - .../HOS/Services/Am/Idle/IPolicyManagerSystem.cs | 8 + Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs | 9 - .../HOS/Services/Am/Omm/IOperationModeManager.cs | 8 + Ryujinx.HLE/HOS/Services/Am/OperationMode.cs | 8 - .../HOS/Services/Am/Spsm/IPowerStateInterface.cs | 8 + Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs | 27 - Ryujinx.HLE/HOS/Services/Am/Tcap/IManager.cs | 8 + Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs | 413 +++++ Ryujinx.HLE/HOS/Services/Android/Parcel.cs | 58 + .../HOS/Services/Android/Types/BufferEntry.cs | 13 + .../HOS/Services/Android/Types/BufferState.cs | 10 + .../Android/Types/Color/ColorBytePerPixel.cs | 17 + .../Services/Android/Types/Color/ColorComponent.cs | 42 + .../Services/Android/Types/Color/ColorDataType.cs | 9 + .../Services/Android/Types/Color/ColorFormat.cs | 235 +++ .../HOS/Services/Android/Types/Color/ColorShift.cs | 10 + .../HOS/Services/Android/Types/Color/ColorSpace.cs | 33 + .../Services/Android/Types/Color/ColorSwizzle.cs | 31 + Ryujinx.HLE/HOS/Services/Android/Types/Fence.cs | 11 + .../HOS/Services/Android/Types/GbpBuffer.cs | 37 + .../Services/Android/Types/GraphicBufferHeader.cs | 21 + .../HOS/Services/Android/Types/HalTransform.cs | 14 + .../HOS/Services/Android/Types/MultiFence.cs | 23 + .../HOS/Services/Android/Types/NvGraphicBuffer.cs | 41 + .../Android/Types/NvGraphicBufferSurface.cs | 44 + .../Android/Types/NvGraphicBufferSurfaceArray.cs | 39 + .../Services/Android/Types/QueueBufferObject.cs | 35 + Ryujinx.HLE/HOS/Services/Android/Types/Rect.cs | 13 + Ryujinx.HLE/HOS/Services/Apm/CpuBoostMode.cs | 9 - Ryujinx.HLE/HOS/Services/Apm/IManager.cs | 3 +- .../HOS/Services/Apm/PerformanceConfiguration.cs | 22 - Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs | 8 - Ryujinx.HLE/HOS/Services/Apm/Types/CpuBoostMode.cs | 9 + .../Services/Apm/Types/PerformanceConfiguration.cs | 22 + .../HOS/Services/Apm/Types/PerformanceMode.cs | 8 + .../HOS/Services/Arp/ApplicationLaunchProperty.cs | 43 + Ryujinx.HLE/HOS/Services/Arp/IReader.cs | 8 + Ryujinx.HLE/HOS/Services/Arp/IWriter.cs | 8 + .../HOS/Services/Aud/AudioOut/AudioOutData.cs | 14 - Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs | 163 -- .../HOS/Services/Aud/AudioRenderer/AudioConsts.cs | 8 - .../HOS/Services/Aud/AudioRenderer/BehaviorIn.cs | 11 - .../HOS/Services/Aud/AudioRenderer/BiquadFilter.cs | 16 - .../Services/Aud/AudioRenderer/IAudioRenderer.cs | 404 ----- .../Aud/AudioRenderer/MemoryPoolContext.cs | 12 - .../HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs | 14 - .../Services/Aud/AudioRenderer/MemoryPoolOut.cs | 12 - .../Services/Aud/AudioRenderer/MemoryPoolState.cs | 13 - .../HOS/Services/Aud/AudioRenderer/PlayState.cs | 9 - .../HOS/Services/Aud/AudioRenderer/Resampler.cs | 191 --- .../Services/Aud/AudioRenderer/UpdateDataHeader.cs | 22 - .../Aud/AudioRenderer/VoiceChannelResourceIn.cs | 10 - .../HOS/Services/Aud/AudioRenderer/VoiceContext.cs | 199 --- .../HOS/Services/Aud/AudioRenderer/VoiceIn.cs | 49 - .../HOS/Services/Aud/AudioRenderer/VoiceOut.cs | 12 - .../HOS/Services/Aud/AudioRenderer/WaveBuffer.cs | 20 - .../HOS/Services/Aud/AudioRendererParameter.cs | 22 - Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs | 236 --- Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs | 162 -- .../HOS/Services/Aud/IAudioRendererManager.cs | 192 --- .../HOS/Services/Aud/IHardwareOpusDecoder.cs | 81 - .../Services/Aud/IHardwareOpusDecoderManager.cs | 63 - Ryujinx.HLE/HOS/Services/Aud/ResultCode.cs | 15 - Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs | 13 - .../Services/Audio/AudioOutManager/IAudioOut.cs | 163 ++ .../Audio/AudioOutManager/Types/AudioOutData.cs | 14 + .../Audio/AudioRendererManager/IAudioDevice.cs | 236 +++ .../Audio/AudioRendererManager/IAudioRenderer.cs | 405 +++++ .../AudioRendererManager/MemoryPoolContext.cs | 12 + .../Audio/AudioRendererManager/Resampler.cs | 191 +++ .../AudioRendererManager/Types/AudioConsts.cs | 8 + .../Types/AudioRendererParameter.cs | 22 + .../Audio/AudioRendererManager/Types/BehaviorIn.cs | 11 + .../AudioRendererManager/Types/BiquadFilter.cs | 16 + .../AudioRendererManager/Types/MemoryPoolIn.cs | 14 + .../AudioRendererManager/Types/MemoryPoolOut.cs | 12 + .../AudioRendererManager/Types/MemoryPoolState.cs | 13 + .../Audio/AudioRendererManager/Types/PlayState.cs | 9 + .../AudioRendererManager/Types/UpdateDataHeader.cs | 22 + .../Types/VoiceChannelResourceIn.cs | 10 + .../Audio/AudioRendererManager/Types/VoiceIn.cs | 49 + .../Audio/AudioRendererManager/Types/VoiceOut.cs | 12 + .../Audio/AudioRendererManager/Types/WaveBuffer.cs | 20 + .../Audio/AudioRendererManager/VoiceContext.cs | 199 +++ .../IHardwareOpusDecoder.cs | 81 + Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs | 8 + Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs | 8 + .../HOS/Services/Audio/IAudioInManagerForApplet.cs | 8 + .../Services/Audio/IAudioInManagerForDebugger.cs | 8 + Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs | 162 ++ .../Services/Audio/IAudioOutManagerForApplet.cs | 8 + .../Services/Audio/IAudioOutManagerForDebugger.cs | 8 + .../HOS/Services/Audio/IAudioRendererManager.cs | 193 +++ .../Audio/IAudioRendererManagerForApplet.cs | 8 + .../Audio/IAudioRendererManagerForDebugger.cs | 8 + .../HOS/Services/Audio/IAudioSnoopManager.cs | 8 + .../Services/Audio/IFinalOutputRecorderManager.cs | 8 + .../Audio/IFinalOutputRecorderManagerForApplet.cs | 8 + .../IFinalOutputRecorderManagerForDebugger.cs | 8 + .../Services/Audio/IHardwareOpusDecoderManager.cs | 65 + Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs | 15 + .../HOS/Services/Audio/Types/SampleFormat.cs | 13 + Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs | 9 - .../Services/Bcat/IDeliveryCacheStorageService.cs | 47 - Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs | 3 +- .../Services/Bcat/ServiceCreator/IBcatService.cs | 9 + .../ServiceCreator/IDeliveryCacheStorageService.cs | 47 + .../HOS/Services/Bgtc/IStateControlService.cs | 8 + Ryujinx.HLE/HOS/Services/Bgtc/ITaskService.cs | 8 + .../BluetoothDriver/BluetoothEventManager.cs | 25 + .../Services/Bluetooth/BluetoothEventManager.cs | 25 - .../HOS/Services/Bluetooth/IBluetoothDriver.cs | 3 +- .../HOS/Services/Bluetooth/IBluetoothUser.cs | 3 +- Ryujinx.HLE/HOS/Services/Bpc/IRtcManager.cs | 34 - Ryujinx.HLE/HOS/Services/Bsd/BsdIoctl.cs | 7 - Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs | 13 - Ryujinx.HLE/HOS/Services/Bsd/IClient.cs | 1180 -------------- Ryujinx.HLE/HOS/Services/Bsd/PollEvent.cs | 28 - .../HOS/Services/Btm/BtmUser/IBtmUserCore.cs | 128 ++ Ryujinx.HLE/HOS/Services/Btm/IBtmDebug.cs | 8 + Ryujinx.HLE/HOS/Services/Btm/IBtmSystem.cs | 8 + Ryujinx.HLE/HOS/Services/Btm/IBtmUser.cs | 6 +- Ryujinx.HLE/HOS/Services/Btm/IBtmUserCore.cs | 128 -- .../HOS/Services/Caps/IAlbumApplicationService.cs | 8 + .../HOS/Services/Caps/IAlbumControlService.cs | 8 + .../Services/Caps/IScreenShotApplicationService.cs | 8 + .../HOS/Services/Caps/IScreenShotControlService.cs | 8 + .../HOS/Services/Caps/IScreenshotService.cs | 2 +- Ryujinx.HLE/HOS/Services/Cec/ICecManager.cs | 8 + Ryujinx.HLE/HOS/Services/Erpt/IContext.cs | 8 + Ryujinx.HLE/HOS/Services/Erpt/ISession.cs | 8 + Ryujinx.HLE/HOS/Services/Es/IETicketService.cs | 4 +- Ryujinx.HLE/HOS/Services/Eupld/IControl.cs | 8 + Ryujinx.HLE/HOS/Services/Eupld/IRequest.cs | 8 + Ryujinx.HLE/HOS/Services/Fatal/IPrivateService.cs | 8 + Ryujinx.HLE/HOS/Services/Fatal/IService.cs | 8 + .../Friend/FriendServicePermissionLevel.cs | 19 - .../Friend/IDaemonSuspendSessionService.cs | 12 - Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs | 169 -- .../HOS/Services/Friend/IFriendServiceTypes.cs | 104 -- .../HOS/Services/Friend/INotificationService.cs | 174 -- Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs | 1 + .../Services/Friend/NotificationEventHandler.cs | 83 - .../ServiceCreator/FriendService/Types/Friend.cs | 29 + .../FriendService/Types/FriendFilter.cs | 24 + .../FriendService/Types/PresenceStatus.cs | 9 + .../FriendService/Types/PresenceStatusFilter.cs | 10 + .../FriendService/Types/UserPresence.cs | 27 + .../ServiceCreator/IDaemonSuspendSessionService.cs | 12 + .../Friend/ServiceCreator/IFriendService.cs | 170 ++ .../Friend/ServiceCreator/INotificationService.cs | 175 ++ .../NotificationEventHandler.cs | 83 + .../Types/NotificationEventType.cs | 9 + .../NotificationService/Types/NotificationInfo.cs | 15 + .../Types/FriendServicePermissionLevel.cs | 19 + .../Fs/FileSystemProxy/FileSystemProxyHelper.cs | 144 ++ .../HOS/Services/Fs/FileSystemProxy/IDirectory.cs | 84 + .../HOS/Services/Fs/FileSystemProxy/IFile.cs | 136 ++ .../HOS/Services/Fs/FileSystemProxy/IFileSystem.cs | 324 ++++ .../HOS/Services/Fs/FileSystemProxy/IStorage.cs | 65 + Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs | 272 ++++ .../HOS/Services/Fs/IFileSystemProxyForLoader.cs | 8 + Ryujinx.HLE/HOS/Services/Fs/IProgramRegistry.cs | 8 + Ryujinx.HLE/HOS/Services/Fs/ResultCode.cs | 16 + .../HOS/Services/Fs/Types/FileSystemType.cs | 12 + .../HOS/Services/FspSrv/FileSystemHelper.cs | 144 -- Ryujinx.HLE/HOS/Services/FspSrv/FileSystemType.cs | 12 - Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs | 84 - Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs | 136 -- Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs | 324 ---- .../HOS/Services/FspSrv/IFileSystemProxy.cs | 271 ---- Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs | 65 - Ryujinx.HLE/HOS/Services/FspSrv/ResultCode.cs | 16 - .../HOS/Services/Glue/ApplicationLaunchProperty.cs | 43 - Ryujinx.HLE/HOS/Services/Grc/IGrcService.cs | 8 + .../HOS/Services/Grc/IRemoteVideoTransfer.cs | 8 + Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs | 41 - Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs | 46 + .../Hid/HidServer/IActiveVibrationDeviceList.cs | 16 + .../HOS/Services/Hid/HidServer/IAppletResource.cs | 31 + Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs | 21 - Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs | 46 - Ryujinx.HLE/HOS/Services/Hid/HidVibration.cs | 29 - .../HOS/Services/Hid/IActiveVibrationDeviceList.cs | 16 - Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs | 31 - Ryujinx.HLE/HOS/Services/Hid/IHidDebugServer.cs | 8 + Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 1 + Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs | 8 + Ryujinx.HLE/HOS/Services/Hid/IHidbusServer.cs | 8 + Ryujinx.HLE/HOS/Services/Hid/ISystemServer.cs | 8 + .../HOS/Services/Hid/Irs/IIrSensorServer.cs | 9 +- .../HOS/Services/Hid/Irs/IIrSensorSystemServer.cs | 8 + Ryujinx.HLE/HOS/Services/Hid/NpadIdType.cs | 16 - .../Types/Npad/HidNpadHandheldActivationMode.cs | 9 + .../HOS/Services/Hid/Types/Npad/HidNpadIdType.cs | 16 + .../Hid/Types/Npad/HidNpadJoyAssignmentMode.cs | 8 + .../Hid/Types/Npad/HidNpadJoyDeviceType.cs | 8 + .../Services/Hid/Types/Npad/HidNpadJoyHoldType.cs | 8 + .../HOS/Services/Hid/Types/Npad/HidNpadStyle.cs | 16 + .../Types/SixAxis/HidAccelerometerParameters.cs | 8 + .../Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs | 9 + .../Hid/Types/SixAxis/HidSensorFusionParameters.cs | 8 + .../Types/Vibration/HidVibrationDevicePosition.cs | 9 + .../Hid/Types/Vibration/HidVibrationDeviceType.cs | 8 + .../Hid/Types/Vibration/HidVibrationDeviceValue.cs | 8 + .../Hid/Types/Vibration/HidVibrationValue.cs | 10 + Ryujinx.HLE/HOS/Services/Ins/IReceiverManager.cs | 8 + Ryujinx.HLE/HOS/Services/Ins/ISenderManager.cs | 8 + Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs | 8 + .../HOS/Services/Ldn/IMonitorServiceCreator.cs | 8 + .../HOS/Services/Ldn/ISystemServiceCreator.cs | 8 + .../HOS/Services/Ldn/IUserServiceCreator.cs | 8 + .../HOS/Services/Ldn/Lp2p/IServiceCreator.cs | 9 + .../HOS/Services/Ldr/IDebugMonitorInterface.cs | 8 + .../HOS/Services/Ldr/IProcessManagerInterface.cs | 8 + Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs | 82 +- Ryujinx.HLE/HOS/Services/Ldr/IShellInterface.cs | 8 + Ryujinx.HLE/HOS/Services/Ldr/Types/NroInfo.cs | 35 + Ryujinx.HLE/HOS/Services/Ldr/Types/NrrHeader.cs | 38 + Ryujinx.HLE/HOS/Services/Ldr/Types/NrrInfo.cs | 18 + Ryujinx.HLE/HOS/Services/Lm/ILogService.cs | 2 + Ryujinx.HLE/HOS/Services/Lm/ILogger.cs | 86 - Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs | 18 - Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs | 11 - Ryujinx.HLE/HOS/Services/Lm/LogService/ILogger.cs | 86 + .../HOS/Services/Lm/LogService/Types/LmLogField.cs | 18 + .../HOS/Services/Lm/LogService/Types/LmLogLevel.cs | 11 + Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs | 254 --- .../HOS/Services/Lr/ILocationResolverManager.cs | 21 - Ryujinx.HLE/HOS/Services/Lr/ResultCode.cs | 13 - Ryujinx.HLE/HOS/Services/Mig/IService.cs | 8 + Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs | 7 - .../Services/Ncm/Lr/ILocationResolverManager.cs | 22 + .../LocationResolverManager/ILocationResolver.cs | 254 +++ Ryujinx.HLE/HOS/Services/Ncm/Lr/ResultCode.cs | 13 + Ryujinx.HLE/HOS/Services/News/IServiceCreator.cs | 12 + Ryujinx.HLE/HOS/Services/Nfc/IAmManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nfc/ISystemManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nfc/IUserManager.cs | 8 + .../HOS/Services/Nfc/Mifare/IUserManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs | 20 - Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs | 13 - Ryujinx.HLE/HOS/Services/Nfc/Nfp/IDebugManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nfc/Nfp/ISystemManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs | 336 ---- Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs | 8 - .../HOS/Services/Nfc/Nfp/UserManager/IUser.cs | 338 ++++ .../Services/Nfc/Nfp/UserManager/Types/Device.cs | 20 + .../Nfc/Nfp/UserManager/Types/DeviceState.cs | 13 + .../Services/Nfc/Nfp/UserManager/Types/State.cs | 8 + Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs | 9 + .../HOS/Services/Nifm/GeneralServiceDetail.cs | 8 - .../HOS/Services/Nifm/GeneralServiceManager.cs | 30 - Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs | 92 -- Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs | 90 - Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs | 2 + .../GeneralService/GeneralServiceManager.cs | 30 + .../GeneralService/Types/GeneralServiceDetail.cs | 8 + .../Services/Nifm/StaticService/IGeneralService.cs | 93 ++ .../HOS/Services/Nifm/StaticService/IRequest.cs | 90 + .../HOS/Services/Nim/INetworkInstallManager.cs | 8 + .../Nim/IShopServiceAccessServerInterface.cs | 8 + .../Nim/IShopServiceAccessSystemInterface.cs | 8 + .../HOS/Services/Nim/IShopServiceManager.cs | 8 + Ryujinx.HLE/HOS/Services/Nim/Ntc/IStaticService.cs | 8 + .../INotificationServicesForApplication.cs | 8 + .../Notification/INotificationServicesForSystem.cs | 8 + Ryujinx.HLE/HOS/Services/Npns/INpnsSystem.cs | 8 + Ryujinx.HLE/HOS/Services/Npns/INpnsUser.cs | 8 + Ryujinx.HLE/HOS/Services/Ns/IDevelopInterface.cs | 8 + .../HOS/Services/Ns/IServiceGetterInterface.cs | 3 + Ryujinx.HLE/HOS/Services/Nsd/FqdnResolver.cs | 131 -- Ryujinx.HLE/HOS/Services/Nsd/IManager.cs | 267 --- Ryujinx.HLE/HOS/Services/Nsd/NsdSettings.cs | 9 - Ryujinx.HLE/HOS/Services/Nsd/ResultCode.cs | 19 - .../HOS/Services/Nv/INvDrvDebugFSServices.cs | 8 + Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs | 10 +- Ryujinx.HLE/HOS/Services/Nv/INvGemControl.cs | 8 + Ryujinx.HLE/HOS/Services/Nv/INvGemCoreDump.cs | 8 + .../Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs | 330 ++++ .../NvGpuAS/Types/NvGpuASAllocSpace.cs | 11 + .../Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs | 200 +++ .../NvGpuAS/Types/NvGpuASMapBufferEx.cs | 13 + .../Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs | 12 + .../NvGpuAS/Types/NvGpuASUnmapBuffer.cs | 7 + .../Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs | 190 +++ .../NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs | 8 + .../NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs | 43 + .../NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs | 11 + .../NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs | 7 + .../NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs | 16 + .../NvHostChannel/NvHostChannelIoctl.cs | 371 +++++ .../NvDrvServices/NvHostChannel/Types/NvChannel.cs | 9 + .../NvHostChannel/Types/NvChannelPriority.cs | 9 + .../NvHostChannel/Types/NvHostChannelCmdBuf.cs | 12 + .../Types/NvHostChannelGetParamArg.cs | 11 + .../NvHostChannel/Types/NvHostChannelMapBuffer.cs | 12 + .../NvHostChannel/Types/NvHostChannelSubmit.cs | 13 + .../Types/NvHostChannelSubmitGpfifo.cs | 11 + .../Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs | 400 +++++ .../NvHostCtrl/Types/NvHostCtrlSyncPtRead.cs | 8 + .../NvHostCtrl/Types/NvHostCtrlSyncPtWait.cs | 9 + .../NvHostCtrl/Types/NvHostCtrlSyncPtWaitEx.cs | 10 + .../NvHostCtrl/Types/NvHostCtrlUserCtx.cs | 19 + .../NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs | 10 + .../NvHostCtrl/Types/NvHostEventState.cs | 10 + .../NvDrvServices/NvHostCtrl/Types/NvHostSyncPt.cs | 107 ++ .../Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs | 300 ++++ .../Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs | 12 + .../Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs | 8 + .../Nv/NvDrvServices/NvMap/Types/NvMapFree.cs | 11 + .../Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs | 8 + .../Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs | 8 + .../Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs | 38 + .../NvDrvServices/NvMap/Types/NvMapHandleParam.cs | 12 + .../Nv/NvDrvServices/NvMap/Types/NvMapParam.cs | 9 + Ryujinx.HLE/HOS/Services/Nv/NvFd.cs | 12 - .../HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs | 11 - Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs | 200 --- .../HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs | 330 ---- .../HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs | 13 - .../HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs | 12 - .../HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs | 7 - .../Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs | 8 - .../Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs | 43 - .../Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs | 11 - .../HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs | 187 --- .../Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs | 7 - .../Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs | 16 - .../HOS/Services/Nv/NvHostChannel/NvChannel.cs | 9 - .../Services/Nv/NvHostChannel/NvChannelPriority.cs | 9 - .../Nv/NvHostChannel/NvHostChannelCmdBuf.cs | 12 - .../Nv/NvHostChannel/NvHostChannelGetParamArg.cs | 11 - .../Nv/NvHostChannel/NvHostChannelIoctl.cs | 371 ----- .../Nv/NvHostChannel/NvHostChannelMapBuffer.cs | 12 - .../Nv/NvHostChannel/NvHostChannelSubmit.cs | 13 - .../Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs | 11 - .../HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs | 399 ----- .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs | 8 - .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs | 9 - .../Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs | 10 - .../Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs | 19 - .../HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs | 10 - .../HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs | 10 - .../HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs | 107 -- Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs | 12 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs | 8 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs | 11 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs | 8 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs | 8 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs | 38 - .../HOS/Services/Nv/NvMap/NvMapHandleParam.cs | 12 - Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs | 300 ---- Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs | 9 - Ryujinx.HLE/HOS/Services/Nv/NvResult.cs | 14 - Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs | 12 + Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs | 14 + .../Services/Olsc/IOlscServiceForSystemService.cs | 8 + Ryujinx.HLE/HOS/Services/Ovln/IReceiverService.cs | 8 + Ryujinx.HLE/HOS/Services/Ovln/ISenderService.cs | 8 + Ryujinx.HLE/HOS/Services/Pcie/ILogManager.cs | 8 + Ryujinx.HLE/HOS/Services/Pcie/IManager.cs | 8 + .../HOS/Services/Pctl/IParentalControlService.cs | 41 - .../Pctl/IParentalControlServiceFactory.cs | 2 + .../IParentalControlService.cs | 41 + .../Services/Pcv/Bpc/IBoardPowerControlManager.cs | 8 + Ryujinx.HLE/HOS/Services/Pcv/Bpc/IRtcManager.cs | 34 + .../HOS/Services/Pcv/Clkrst/IArbitrationManager.cs | 8 + .../HOS/Services/Pcv/Clkrst/IClkrstManager.cs | 9 + Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs | 8 + .../HOS/Services/Pcv/Rgltr/IRegulatorManager.cs | 8 + Ryujinx.HLE/HOS/Services/Pcv/Rtc/IUnknown1.cs | 8 + Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs | 127 -- Ryujinx.HLE/HOS/Services/Pm/IBootModeInterface.cs | 8 + .../HOS/Services/Pm/IDebugMonitorInterface.cs | 8 + Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs | 1 + Ryujinx.HLE/HOS/Services/Psc/IPmControl.cs | 8 + Ryujinx.HLE/HOS/Services/Psc/IPmService.cs | 8 + Ryujinx.HLE/HOS/Services/Psc/IPmUnknown.cs | 8 + Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs | 52 - Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs | 88 - Ryujinx.HLE/HOS/Services/Ptm/Fan/IManager.cs | 8 + Ryujinx.HLE/HOS/Services/Ptm/Fgm/IDebugger.cs | 8 + Ryujinx.HLE/HOS/Services/Ptm/Fgm/ISession.cs | 10 + Ryujinx.HLE/HOS/Services/Ptm/Pcm/IManager.cs | 8 + Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmServer.cs | 45 + Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs | 88 + .../HOS/Services/Ptm/Psm/Types/ChargerType.cs | 9 + Ryujinx.HLE/HOS/Services/Ptm/Tc/IManager.cs | 8 + .../HOS/Services/Ptm/Ts/IMeasurementServer.cs | 8 + Ryujinx.HLE/HOS/Services/Sdb/Avm/IAvmService.cs | 8 + .../HOS/Services/Sdb/Mii/IImageDatabaseService.cs | 8 + Ryujinx.HLE/HOS/Services/Sdb/Mii/IStaticService.cs | 9 + Ryujinx.HLE/HOS/Services/Sdb/Pdm/INotifyService.cs | 8 + Ryujinx.HLE/HOS/Services/Sdb/Pdm/IQueryService.cs | 8 + .../HOS/Services/Sdb/Pl/ISharedFontManager.cs | 128 ++ Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs | 109 -- .../HOS/Services/Set/ISystemSettingsServer.cs | 198 --- Ryujinx.HLE/HOS/Services/Set/NxSettings.cs | 1711 -------------------- Ryujinx.HLE/HOS/Services/Set/ResultCode.cs | 12 - .../Services/Settings/IFactorySettingsServer.cs | 8 + .../Settings/IFirmwareDebugSettingsServer.cs | 8 + .../HOS/Services/Settings/ISettingsServer.cs | 109 ++ .../HOS/Services/Settings/ISystemSettingsServer.cs | 198 +++ Ryujinx.HLE/HOS/Services/Settings/NxSettings.cs | 1711 ++++++++++++++++++++ Ryujinx.HLE/HOS/Services/Settings/ResultCode.cs | 12 + Ryujinx.HLE/HOS/Services/Sfdnsres/GaiError.cs | 22 - Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs | 387 ----- Ryujinx.HLE/HOS/Services/Sfdnsres/NetDBError.cs | 13 - Ryujinx.HLE/HOS/Services/Sm/IManagerInterface.cs | 8 + Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs | 1180 ++++++++++++++ .../HOS/Services/Sockets/Bsd/ServerInterface.cs | 8 + .../HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs | 7 + .../HOS/Services/Sockets/Bsd/Types/BsdSocket.cs | 13 + .../HOS/Services/Sockets/Bsd/Types/PollEvent.cs | 28 + .../HOS/Services/Sockets/Ethc/IEthInterface.cs | 8 + .../Services/Sockets/Ethc/IEthInterfaceGroup.cs | 8 + Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs | 268 +++ .../Services/Sockets/Nsd/Manager/FqdnResolver.cs | 131 ++ Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs | 19 + .../HOS/Services/Sockets/Nsd/Types/NsdSettings.cs | 9 + .../HOS/Services/Sockets/Sfdnsres/IResolver.cs | 387 +++++ .../Services/Sockets/Sfdnsres/Types/GaiError.cs | 22 + .../Services/Sockets/Sfdnsres/Types/NetDBError.cs | 13 + Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs | 13 + Ryujinx.HLE/HOS/Services/Srepo/ISrepoService.cs | 9 + Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs | 7 - Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs | 1 + .../HOS/Services/Ssl/SslService/ISslContext.cs | 7 + Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs | 105 -- .../Time/Clock/StandardNetworkSystemClockCore.cs | 2 +- .../Services/Time/Clock/StandardSteadyClockCore.cs | 2 +- .../Time/Clock/TickBasedSteadyClockCore.cs | 3 +- .../HOS/Services/Time/Clock/Types/ClockSnapshot.cs | 41 + .../Time/Clock/Types/SteadyClockTimePoint.cs | 34 + .../Time/Clock/Types/SystemClockContext.cs | 11 + .../HOS/Services/Time/Clock/Types/TimeSpanType.cs | 32 + Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs | 8 + .../HOS/Services/Time/IPowerStateRequestHandler.cs | 8 + Ryujinx.HLE/HOS/Services/Time/IStaticService.cs | 2 + Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs | 91 -- Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs | 107 -- .../HOS/Services/Time/ITimeServiceManager.cs | 8 + Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs | 218 --- .../HOS/Services/Time/ITimeZoneServiceTypes.cs | 128 -- .../Services/Time/StaticService/ISteadyClock.cs | 91 ++ .../Services/Time/StaticService/ISystemClock.cs | 107 ++ .../Time/StaticService/ITimeZoneService.cs | 218 +++ Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs | 17 - Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs | 12 +- .../HOS/Services/Time/TimeZone/TimeZoneManager.cs | 10 +- .../Time/TimeZone/Types/CalendarAdditionalInfo.cs | 22 + .../Services/Time/TimeZone/Types/CalendarInfo.cs | 11 + .../Services/Time/TimeZone/Types/CalendarTime.cs | 15 + .../Services/Time/TimeZone/Types/TimeTypeInfo.cs | 27 + .../Services/Time/TimeZone/Types/TimeZoneRule.cs | 39 + .../HOS/Services/Time/TimeZone/Types/TzifHeader.cs | 34 + .../HOS/Services/Time/Types/TimePermissions.cs | 17 + Ryujinx.HLE/HOS/Services/Usb/IClientRootSession.cs | 9 + Ryujinx.HLE/HOS/Services/Usb/IDsService.cs | 8 + Ryujinx.HLE/HOS/Services/Usb/IPdCradleManager.cs | 8 + Ryujinx.HLE/HOS/Services/Usb/IPdManager.cs | 8 + Ryujinx.HLE/HOS/Services/Usb/IPmService.cs | 8 + Ryujinx.HLE/HOS/Services/Usb/IUnknown1.cs | 8 + Ryujinx.HLE/HOS/Services/Usb/IUnknown2.cs | 8 + Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs | 366 ----- Ryujinx.HLE/HOS/Services/Vi/Display.cs | 12 - Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs | 165 -- .../HOS/Services/Vi/IApplicationDisplayService.cs | 287 ---- .../HOS/Services/Vi/IApplicationRootService.cs | 2 + Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs | 99 -- .../HOS/Services/Vi/IManagerDisplayService.cs | 61 - Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs | 2 + .../HOS/Services/Vi/ISystemDisplayService.cs | 54 - Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs | 2 + Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 508 ------ Ryujinx.HLE/HOS/Services/Vi/Parcel.cs | 58 - .../ApplicationDisplayService/Display.cs | 12 + .../ApplicationDisplayService/IHOSBinderDriver.cs | 99 ++ .../IManagerDisplayService.cs | 61 + .../ISystemDisplayService.cs | 54 + .../Types/DestinationScalingMode.cs | 11 + .../Types/SourceScalingMode.cs | 11 + .../Vi/RootService/IApplicationDisplayService.cs | 288 ++++ Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs | 20 - Ryujinx.HLE/HOS/Services/Wlan/IInfraManager.cs | 8 + .../HOS/Services/Wlan/ILocalGetActionFrame.cs | 8 + Ryujinx.HLE/HOS/Services/Wlan/ILocalGetFrame.cs | 8 + Ryujinx.HLE/HOS/Services/Wlan/ILocalManager.cs | 8 + Ryujinx.HLE/HOS/Services/Wlan/ISocketGetFrame.cs | 8 + Ryujinx.HLE/HOS/Services/Wlan/ISocketManager.cs | 8 + Ryujinx.HLE/HOS/Services/Wlan/IUnknown1.cs | 8 + Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs | 2 +- Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs | 2 +- 554 files changed, 17114 insertions(+), 15873 deletions(-) delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/Account/AccountState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/Account/AccountUtils.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/Account/UserProfile.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/IProfile.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Acc/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/AccountUtils.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForAdministrator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForSystemService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IManagerForApplication.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/IProfile.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/Types/AccountState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/Dauth/IService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Account/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IApplicationCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAudioController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDebugFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IGlobalStateController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/FocusState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/MessageInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/OperationMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletAE/Storage/StorageHelper.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/FocusState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IAudioController.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/ISelfController.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IStorage.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/IWindowController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/Idle/IPolicyManagerSystem.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/Omm/IOperationModeManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/OperationMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/Spsm/IPowerStateInterface.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/Tcap/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Parcel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/BufferEntry.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/BufferState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorBytePerPixel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorComponent.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorDataType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorFormat.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorShift.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSpace.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSwizzle.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Fence.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/GbpBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/GraphicBufferHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/HalTransform.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/MultiFence.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurfaceArray.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/QueueBufferObject.cs create mode 100644 Ryujinx.HLE/HOS/Services/Android/Types/Rect.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Apm/CpuBoostMode.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/Types/CpuBoostMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceConfiguration.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs create mode 100644 Ryujinx.HLE/HOS/Services/Arp/IReader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Arp/IWriter.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/ResultCode.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/Types/AudioOutData.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Audio/Types/SampleFormat.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IBcatService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bgtc/IStateControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bgtc/ITaskService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothDriver/BluetoothEventManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothEventManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bpc/IRtcManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bsd/BsdIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bsd/IClient.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Bsd/PollEvent.cs create mode 100644 Ryujinx.HLE/HOS/Services/Btm/BtmUser/IBtmUserCore.cs create mode 100644 Ryujinx.HLE/HOS/Services/Btm/IBtmDebug.cs create mode 100644 Ryujinx.HLE/HOS/Services/Btm/IBtmSystem.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Btm/IBtmUserCore.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IAlbumApplicationService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IAlbumControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IScreenShotControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Cec/ICecManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Erpt/IContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Erpt/ISession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Eupld/IControl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Eupld/IRequest.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fatal/IPrivateService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fatal/IService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/FriendServicePermissionLevel.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Friend/NotificationEventHandler.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxyForLoader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/IProgramRegistry.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Fs/Types/FileSystemType.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/FileSystemType.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs delete mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/ResultCode.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs create mode 100644 Ryujinx.HLE/HOS/Services/Grc/IGrcService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Grc/IRemoteVideoTransfer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidServer/IActiveVibrationDeviceList.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/HidVibration.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IHidDebugServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IHidbusServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/ISystemServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorSystemServer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/NpadIdType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ins/IReceiverManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ins/ISenderManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldn/IMonitorServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldn/ISystemServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/IDebugMonitorInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/IProcessManagerInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/IShellInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/Types/NroInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/Types/NrrHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ldr/Types/NrrInfo.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lm/ILogger.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/LogService/ILogger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogField.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogLevel.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Lr/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Mig/IService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ncm/Lr/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/News/IServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/IAmManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/ISystemManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/IUserManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Mifare/IUserManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/IDebugManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/ISystemManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/DeviceState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/State.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceDetail.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nim/INetworkInstallManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessSystemInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nim/IShopServiceManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nim/Ntc/IStaticService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForApplication.cs create mode 100644 Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForSystem.cs create mode 100644 Ryujinx.HLE/HOS/Services/Npns/INpnsSystem.cs create mode 100644 Ryujinx.HLE/HOS/Services/Npns/INpnsUser.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ns/IDevelopInterface.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nsd/FqdnResolver.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nsd/IManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nsd/NsdSettings.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nsd/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/INvDrvDebugFSServices.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/INvGemControl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/INvGemCoreDump.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannelPriority.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelCmdBuf.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelGetParamArg.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelMapBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmit.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmitGpfifo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtRead.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWait.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWaitEx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlUserCtx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEventState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostSyncPt.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvFd.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelPriority.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvResult.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs create mode 100644 Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForSystemService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ovln/IReceiverService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ovln/ISenderService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcie/ILogManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcie/IManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Bpc/IBoardPowerControlManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Bpc/IRtcManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IArbitrationManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Rgltr/IRegulatorManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pcv/Rtc/IUnknown1.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pm/IBootModeInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Psc/IPmControl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Psc/IPmService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Psc/IPmUnknown.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Fan/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Fgm/IDebugger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Fgm/ISession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Pcm/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Psm/Types/ChargerType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Tc/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Avm/IAvmService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Mii/IImageDatabaseService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Mii/IStaticService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Pdm/INotifyService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Pdm/IQueryService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Set/NxSettings.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Set/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/IFactorySettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/IFirmwareDebugSettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/ISettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/NxSettings.cs create mode 100644 Ryujinx.HLE/HOS/Services/Settings/ResultCode.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Sfdnsres/GaiError.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Sfdnsres/NetDBError.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sm/IManagerInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Bsd/ServerInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocket.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterfaceGroup.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs create mode 100644 Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Srepo/ISrepoService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ssl/SslService/ISslContext.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IClientRootSession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IDsService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IPdCradleManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IPdManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IPmService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IUnknown1.cs create mode 100644 Ryujinx.HLE/HOS/Services/Usb/IUnknown2.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/Display.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/Parcel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IHOSBinderDriver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DestinationScalingMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/SourceScalingMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/IInfraManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/ILocalGetActionFrame.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/ILocalGetFrame.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/ILocalManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/ISocketGetFrame.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/ISocketManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Wlan/IUnknown1.cs diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 334cba12..86b28320 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -8,6 +8,7 @@ using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Settings; using Ryujinx.HLE.HOS.Services.Sm; using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.HOS.SystemState; @@ -203,7 +204,7 @@ namespace Ryujinx.HLE.HOS // TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate. StandardSteadyClockCore.Instance.ConfigureSetupValue(); - if (Services.Set.NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes)) + if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes)) { TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000); diff --git a/Ryujinx.HLE/HOS/Services/Acc/Account/AccountState.cs b/Ryujinx.HLE/HOS/Services/Acc/Account/AccountState.cs deleted file mode 100644 index 7ed3c26e..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/Account/AccountState.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.SystemState -{ - public enum AccountState - { - Closed, - Open - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/Account/AccountUtils.cs b/Ryujinx.HLE/HOS/Services/Acc/Account/AccountUtils.cs deleted file mode 100644 index 5e7f4dac..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/Account/AccountUtils.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Utilities; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.HLE.HOS.Services.Acc -{ - public class AccountUtils - { - private ConcurrentDictionary _profiles; - - internal UserProfile LastOpenedUser { get; private set; } - - public AccountUtils() - { - _profiles = new ConcurrentDictionary(); - } - - public void AddUser(UInt128 userId, string name) - { - UserProfile profile = new UserProfile(userId, name); - - _profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile); - } - - public void OpenUser(UInt128 userId) - { - if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) - { - (LastOpenedUser = profile).AccountState = AccountState.Open; - } - } - - public void CloseUser(UInt128 userId) - { - if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) - { - profile.AccountState = AccountState.Closed; - } - } - - public int GetUserCount() - { - return _profiles.Count; - } - - internal bool TryGetUser(UInt128 userId, out UserProfile profile) - { - return _profiles.TryGetValue(userId.ToString(), out profile); - } - - internal IEnumerable GetAllUsers() - { - return _profiles.Values; - } - - internal IEnumerable GetOpenedUsers() - { - return _profiles.Values.Where(x => x.AccountState == AccountState.Open); - } - - internal UserProfile GetFirst() - { - return _profiles.First().Value; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/Account/UserProfile.cs b/Ryujinx.HLE/HOS/Services/Acc/Account/UserProfile.cs deleted file mode 100644 index d201d6e7..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/Account/UserProfile.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Ryujinx.HLE.Utilities; -using System; - -namespace Ryujinx.HLE.HOS.SystemState -{ - class UserProfile - { - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - public UInt128 UserId { get; private set; } - - public string Name { get; private set; } - - public long LastModifiedTimestamp { get; private set; } - - public AccountState AccountState { get; set; } - public AccountState OnlinePlayState { get; set; } - - public UserProfile(UInt128 userId, string name) - { - UserId = userId; - Name = name; - - LastModifiedTimestamp = 0; - - AccountState = AccountState.Closed; - OnlinePlayState = AccountState.Closed; - - UpdateTimestamp(); - } - - private void UpdateTimestamp() - { - LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs b/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs deleted file mode 100644 index 23f3eec7..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs +++ /dev/null @@ -1,298 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Glue; -using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Utilities; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Acc -{ - [Service("acc:u0")] - [Service("acc:u1")] - class IAccountService : IpcService - { - private bool _userRegistrationRequestPermitted = false; - - private ApplicationLaunchProperty _applicationLaunchProperty; - - public IAccountService(ServiceCtx context) { } - - [Command(0)] - // GetUserCount() -> i32 - public ResultCode GetUserCount(ServiceCtx context) - { - context.ResponseData.Write(context.Device.System.State.Account.GetUserCount()); - - return ResultCode.Success; - } - - [Command(1)] - // GetUserExistence(nn::account::Uid) -> bool - public ResultCode GetUserExistence(ServiceCtx context) - { - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); - - if (userId.IsNull) - { - return ResultCode.NullArgument; - } - - context.ResponseData.Write(context.Device.System.State.Account.TryGetUser(userId, out _)); - - return ResultCode.Success; - } - - [Command(2)] - // ListAllUsers() -> array - public ResultCode ListAllUsers(ServiceCtx context) - { - return WriteUserList(context, context.Device.System.State.Account.GetAllUsers()); - } - - [Command(3)] - // ListOpenUsers() -> array - public ResultCode ListOpenUsers(ServiceCtx context) - { - return WriteUserList(context, context.Device.System.State.Account.GetOpenedUsers()); - } - - private ResultCode WriteUserList(ServiceCtx context, IEnumerable profiles) - { - if (context.Request.RecvListBuff.Count == 0) - { - return ResultCode.InvalidInputBuffer; - } - - long outputPosition = context.Request.RecvListBuff[0].Position; - long outputSize = context.Request.RecvListBuff[0].Size; - - ulong offset = 0; - - foreach (UserProfile userProfile in profiles) - { - if (offset + 0x10 > (ulong)outputSize) - { - break; - } - - context.Memory.WriteInt64(outputPosition + (long)offset, userProfile.UserId.Low); - context.Memory.WriteInt64(outputPosition + (long)offset + 8, userProfile.UserId.High); - - offset += 0x10; - } - - return ResultCode.Success; - } - - [Command(4)] - // GetLastOpenedUser() -> nn::account::Uid - public ResultCode GetLastOpenedUser(ServiceCtx context) - { - context.Device.System.State.Account.LastOpenedUser.UserId.Write(context.ResponseData); - - return ResultCode.Success; - } - - [Command(5)] - // GetProfile(nn::account::Uid) -> object - public ResultCode GetProfile(ServiceCtx context) - { - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); - - if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile)) - { - Logger.PrintWarning(LogClass.ServiceAcc, $"User 0x{userId} not found!"); - - return ResultCode.UserNotFound; - } - - MakeObject(context, new IProfile(userProfile)); - - // Doesn't occur in our case. - // return ResultCode.NullObject; - - return ResultCode.Success; - } - - [Command(50)] - // IsUserRegistrationRequestPermitted(u64, pid) -> bool - public ResultCode IsUserRegistrationRequestPermitted(ServiceCtx context) - { - // The u64 argument seems to be unused by account. - context.ResponseData.Write(_userRegistrationRequestPermitted); - - return ResultCode.Success; - } - - [Command(51)] - // TrySelectUserWithoutInteraction(bool) -> nn::account::Uid - public ResultCode TrySelectUserWithoutInteraction(ServiceCtx context) - { - if (context.Device.System.State.Account.GetUserCount() != 1) - { - // Invalid UserId. - new UInt128(0, 0).Write(context.ResponseData); - - return 0; - } - - bool baasCheck = context.RequestData.ReadBoolean(); - - if (baasCheck) - { - // This checks something related to baas (online), and then return an invalid UserId if the check in baas returns an error code. - // In our case, we can just log it for now. - - Logger.PrintStub(LogClass.ServiceAcc, new { baasCheck }); - } - - // As we returned an invalid UserId if there is more than one user earlier, now we can return only the first one. - context.Device.System.State.Account.GetFirst().UserId.Write(context.ResponseData); - - return ResultCode.Success; - } - - [Command(100)] - [Command(140)] // 6.0.0+ - // InitializeApplicationInfo(u64, pid) - // Both calls (100, 140) use the same submethod, maybe there's something different further along when arp:r is called? - public ResultCode InitializeApplicationInfo(ServiceCtx context) - { - if (_applicationLaunchProperty != null) - { - return ResultCode.ApplicationLaunchPropertyAlreadyInit; - } - - // The u64 argument seems to be unused by account. - long unknown = context.RequestData.ReadInt64(); - - // TODO: Account actually calls nn::arp::detail::IReader::GetApplicationLaunchProperty() with the current PID and store the result (ApplicationLaunchProperty) internally. - // For now we can hardcode values, and fix it after GetApplicationLaunchProperty is implemented. - - /* - if (nn::arp::detail::IReader::GetApplicationLaunchProperty() == 0xCC9D) // InvalidProcessId - { - _applicationLaunchProperty = ApplicationLaunchProperty.Default; - - return ResultCode.InvalidArgument; - } - else - */ - { - _applicationLaunchProperty = ApplicationLaunchProperty.GetByPid(context); - } - - Logger.PrintStub(LogClass.ServiceAcc, new { unknown }); - - return ResultCode.Success; - } - - [Command(101)] - // GetBaasAccountManagerForApplication(nn::account::Uid) -> object - public ResultCode GetBaasAccountManagerForApplication(ServiceCtx context) - { - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); - - if (userId.IsNull) - { - return ResultCode.NullArgument; - } - - if (_applicationLaunchProperty == null) - { - return ResultCode.InvalidArgument; - } - - MakeObject(context, new IManagerForApplication(userId, _applicationLaunchProperty)); - - // Doesn't occur in our case. - // return ResultCode.NullObject; - - return ResultCode.Success; - } - - [Command(110)] - // StoreSaveDataThumbnail(nn::account::Uid, buffer) - public ResultCode StoreSaveDataThumbnail(ServiceCtx context) - { - if (_applicationLaunchProperty == null) - { - return ResultCode.InvalidArgument; - } - - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); - - if (userId.IsNull) - { - return ResultCode.NullArgument; - } - - if (context.Request.SendBuff.Count == 0) - { - return ResultCode.InvalidInputBuffer; - } - - long inputPosition = context.Request.SendBuff[0].Position; - long inputSize = context.Request.SendBuff[0].Size; - - if (inputSize != 0x24000) - { - return ResultCode.InvalidInputBufferSize; - } - - byte[] thumbnailBuffer = context.Memory.ReadBytes(inputPosition, inputSize); - - // TODO: Store thumbnailBuffer somewhere, in save data 0x8000000000000010 ? - - Logger.PrintStub(LogClass.ServiceAcc); - - return ResultCode.Success; - } - - [Command(111)] - // ClearSaveDataThumbnail(nn::account::Uid) - public ResultCode ClearSaveDataThumbnail(ServiceCtx context) - { - if (_applicationLaunchProperty == null) - { - return ResultCode.InvalidArgument; - } - - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); - - if (userId.IsNull) - { - return ResultCode.NullArgument; - } - - // TODO: Clear the Thumbnail somewhere, in save data 0x8000000000000010 ? - - Logger.PrintStub(LogClass.ServiceAcc); - - return ResultCode.Success; - } - - [Command(150)] // 6.0.0+ - // IsUserAccountSwitchLocked() -> bool - public ResultCode IsUserAccountSwitchLocked(ServiceCtx context) - { - // TODO : Validate the following check. - /* - if (_applicationLaunchProperty != null) - { - return ResultCode.ApplicationLaunchPropertyAlreadyInit; - } - */ - - // Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current PID and store the result (NACP File) internally. - // But since we use LibHac and we load one Application at a time, it's not necessary. - - context.ResponseData.Write(context.Device.System.ControlData.UserAccountSwitchLock); - - Logger.PrintStub(LogClass.ServiceAcc); - - return ResultCode.Success; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs b/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs deleted file mode 100644 index 8fb901c5..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Glue; -using Ryujinx.HLE.Utilities; - -namespace Ryujinx.HLE.HOS.Services.Acc -{ - class IManagerForApplication : IpcService - { - private UInt128 _userId; - private ApplicationLaunchProperty _applicationLaunchProperty; - - public IManagerForApplication(UInt128 userId, ApplicationLaunchProperty applicationLaunchProperty) - { - _userId = userId; - _applicationLaunchProperty = applicationLaunchProperty; - } - - [Command(0)] - // CheckAvailability() - public ResultCode CheckAvailability(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAcc); - - return ResultCode.Success; - } - - [Command(1)] - // GetAccountId() -> nn::account::NetworkServiceAccountId - public ResultCode GetAccountId(ServiceCtx context) - { - long networkServiceAccountId = 0xcafe; - - Logger.PrintStub(LogClass.ServiceAcc, new { networkServiceAccountId }); - - context.ResponseData.Write(networkServiceAccountId); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs b/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs deleted file mode 100644 index 10210afe..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs +++ /dev/null @@ -1,81 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Utilities; -using System.IO; -using System.Reflection; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Acc -{ - class IProfile : IpcService - { - private UserProfile _profile; - private Stream _profilePictureStream; - - public IProfile(UserProfile profile) - { - _profile = profile; - _profilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg"); - } - - [Command(0)] - // Get() -> (nn::account::profile::ProfileBase, buffer) - public ResultCode Get(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAcc); - - long position = context.Request.ReceiveBuff[0].Position; - - MemoryHelper.FillWithZeros(context.Memory, position, 0x80); - - context.Memory.WriteInt32(position, 0); - context.Memory.WriteInt32(position + 4, 1); - context.Memory.WriteInt64(position + 8, 1); - - return GetBase(context); - } - - [Command(1)] - // GetBase() -> nn::account::profile::ProfileBase - public ResultCode GetBase(ServiceCtx context) - { - _profile.UserId.Write(context.ResponseData); - - context.ResponseData.Write(_profile.LastModifiedTimestamp); - - byte[] username = StringUtils.GetFixedLengthBytes(_profile.Name, 0x20, Encoding.UTF8); - - context.ResponseData.Write(username); - - return ResultCode.Success; - } - - [Command(10)] - // GetImageSize() -> u32 - public ResultCode GetImageSize(ServiceCtx context) - { - context.ResponseData.Write(_profilePictureStream.Length); - - return ResultCode.Success; - } - - [Command(11)] - // LoadImage() -> (u32, buffer) - public ResultCode LoadImage(ServiceCtx context) - { - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferLen = context.Request.ReceiveBuff[0].Size; - - byte[] profilePictureData = new byte[bufferLen]; - - _profilePictureStream.Read(profilePictureData, 0, profilePictureData.Length); - - context.Memory.WriteBytes(bufferPosition, profilePictureData); - - context.ResponseData.Write(_profilePictureStream.Length); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Acc/ResultCode.cs deleted file mode 100644 index 3991875a..00000000 --- a/Ryujinx.HLE/HOS/Services/Acc/ResultCode.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Acc -{ - enum ResultCode - { - ModuleId = 124, - ErrorCodeShift = 9, - - Success = 0, - - NullArgument = (20 << ErrorCodeShift) | ModuleId, - InvalidArgument = (22 << ErrorCodeShift) | ModuleId, - NullInputBuffer = (30 << ErrorCodeShift) | ModuleId, - InvalidInputBufferSize = (31 << ErrorCodeShift) | ModuleId, - InvalidInputBuffer = (32 << ErrorCodeShift) | ModuleId, - ApplicationLaunchPropertyAlreadyInit = (41 << ErrorCodeShift) | ModuleId, - UserNotFound = (100 << ErrorCodeShift) | ModuleId, - NullObject = (302 << ErrorCodeShift) | ModuleId, - UnknownError1 = (341 << ErrorCodeShift) | ModuleId - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/AccountUtils.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/AccountUtils.cs new file mode 100644 index 00000000..7a70025a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/AccountUtils.cs @@ -0,0 +1,67 @@ +using Ryujinx.HLE.Utilities; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + public class AccountUtils + { + private ConcurrentDictionary _profiles; + + internal UserProfile LastOpenedUser { get; private set; } + + public AccountUtils() + { + _profiles = new ConcurrentDictionary(); + } + + public void AddUser(UInt128 userId, string name) + { + UserProfile profile = new UserProfile(userId, name); + + _profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile); + } + + public void OpenUser(UInt128 userId) + { + if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) + { + (LastOpenedUser = profile).AccountState = AccountState.Open; + } + } + + public void CloseUser(UInt128 userId) + { + if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) + { + profile.AccountState = AccountState.Closed; + } + } + + public int GetUserCount() + { + return _profiles.Count; + } + + internal bool TryGetUser(UInt128 userId, out UserProfile profile) + { + return _profiles.TryGetValue(userId.ToString(), out profile); + } + + internal IEnumerable GetAllUsers() + { + return _profiles.Values; + } + + internal IEnumerable GetOpenedUsers() + { + return _profiles.Values.Where(x => x.AccountState == AccountState.Open); + } + + internal UserProfile GetFirst() + { + return _profiles.First().Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForAdministrator.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForAdministrator.cs new file mode 100644 index 00000000..9fb3fb9b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForAdministrator.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + [Service("acc:su")] + class IAccountServiceForAdministrator : IpcService + { + public IAccountServiceForAdministrator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs new file mode 100644 index 00000000..84239539 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs @@ -0,0 +1,294 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Arp; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + [Service("acc:u0")] + class IAccountServiceForApplication : IpcService + { + private bool _userRegistrationRequestPermitted = false; + + private ApplicationLaunchProperty _applicationLaunchProperty; + + public IAccountServiceForApplication(ServiceCtx context) { } + + [Command(0)] + // GetUserCount() -> i32 + public ResultCode GetUserCount(ServiceCtx context) + { + context.ResponseData.Write(context.Device.System.State.Account.GetUserCount()); + + return ResultCode.Success; + } + + [Command(1)] + // GetUserExistence(nn::account::Uid) -> bool + public ResultCode GetUserExistence(ServiceCtx context) + { + UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + + if (userId.IsNull) + { + return ResultCode.NullArgument; + } + + context.ResponseData.Write(context.Device.System.State.Account.TryGetUser(userId, out _)); + + return ResultCode.Success; + } + + [Command(2)] + // ListAllUsers() -> array + public ResultCode ListAllUsers(ServiceCtx context) + { + return WriteUserList(context, context.Device.System.State.Account.GetAllUsers()); + } + + [Command(3)] + // ListOpenUsers() -> array + public ResultCode ListOpenUsers(ServiceCtx context) + { + return WriteUserList(context, context.Device.System.State.Account.GetOpenedUsers()); + } + + private ResultCode WriteUserList(ServiceCtx context, IEnumerable profiles) + { + if (context.Request.RecvListBuff.Count == 0) + { + return ResultCode.InvalidInputBuffer; + } + + long outputPosition = context.Request.RecvListBuff[0].Position; + long outputSize = context.Request.RecvListBuff[0].Size; + + ulong offset = 0; + + foreach (UserProfile userProfile in profiles) + { + if (offset + 0x10 > (ulong)outputSize) + { + break; + } + + context.Memory.WriteInt64(outputPosition + (long)offset, userProfile.UserId.Low); + context.Memory.WriteInt64(outputPosition + (long)offset + 8, userProfile.UserId.High); + + offset += 0x10; + } + + return ResultCode.Success; + } + + [Command(4)] + // GetLastOpenedUser() -> nn::account::Uid + public ResultCode GetLastOpenedUser(ServiceCtx context) + { + context.Device.System.State.Account.LastOpenedUser.UserId.Write(context.ResponseData); + + return ResultCode.Success; + } + + [Command(5)] + // GetProfile(nn::account::Uid) -> object + public ResultCode GetProfile(ServiceCtx context) + { + UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + + if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile)) + { + Logger.PrintWarning(LogClass.ServiceAcc, $"User 0x{userId} not found!"); + + return ResultCode.UserNotFound; + } + + MakeObject(context, new IProfile(userProfile)); + + // Doesn't occur in our case. + // return ResultCode.NullObject; + + return ResultCode.Success; + } + + [Command(50)] + // IsUserRegistrationRequestPermitted(u64, pid) -> bool + public ResultCode IsUserRegistrationRequestPermitted(ServiceCtx context) + { + // The u64 argument seems to be unused by account. + context.ResponseData.Write(_userRegistrationRequestPermitted); + + return ResultCode.Success; + } + + [Command(51)] + // TrySelectUserWithoutInteraction(bool) -> nn::account::Uid + public ResultCode TrySelectUserWithoutInteraction(ServiceCtx context) + { + if (context.Device.System.State.Account.GetUserCount() != 1) + { + // Invalid UserId. + new UInt128(0, 0).Write(context.ResponseData); + + return 0; + } + + bool baasCheck = context.RequestData.ReadBoolean(); + + if (baasCheck) + { + // This checks something related to baas (online), and then return an invalid UserId if the check in baas returns an error code. + // In our case, we can just log it for now. + + Logger.PrintStub(LogClass.ServiceAcc, new { baasCheck }); + } + + // As we returned an invalid UserId if there is more than one user earlier, now we can return only the first one. + context.Device.System.State.Account.GetFirst().UserId.Write(context.ResponseData); + + return ResultCode.Success; + } + + [Command(100)] + [Command(140)] // 6.0.0+ + // InitializeApplicationInfo(u64, pid) + // Both calls (100, 140) use the same submethod, maybe there's something different further along when arp:r is called? + public ResultCode InitializeApplicationInfo(ServiceCtx context) + { + if (_applicationLaunchProperty != null) + { + return ResultCode.ApplicationLaunchPropertyAlreadyInit; + } + + // The u64 argument seems to be unused by account. + long unknown = context.RequestData.ReadInt64(); + + // TODO: Account actually calls nn::arp::detail::IReader::GetApplicationLaunchProperty() with the current PID and store the result (ApplicationLaunchProperty) internally. + // For now we can hardcode values, and fix it after GetApplicationLaunchProperty is implemented. + + /* + if (nn::arp::detail::IReader::GetApplicationLaunchProperty() == 0xCC9D) // InvalidProcessId + { + _applicationLaunchProperty = ApplicationLaunchProperty.Default; + + return ResultCode.InvalidArgument; + } + else + */ + { + _applicationLaunchProperty = ApplicationLaunchProperty.GetByPid(context); + } + + Logger.PrintStub(LogClass.ServiceAcc, new { unknown }); + + return ResultCode.Success; + } + + [Command(101)] + // GetBaasAccountManagerForApplication(nn::account::Uid) -> object + public ResultCode GetBaasAccountManagerForApplication(ServiceCtx context) + { + UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + + if (userId.IsNull) + { + return ResultCode.NullArgument; + } + + if (_applicationLaunchProperty == null) + { + return ResultCode.InvalidArgument; + } + + MakeObject(context, new IManagerForApplication(userId, _applicationLaunchProperty)); + + // Doesn't occur in our case. + // return ResultCode.NullObject; + + return ResultCode.Success; + } + + [Command(110)] + // StoreSaveDataThumbnail(nn::account::Uid, buffer) + public ResultCode StoreSaveDataThumbnail(ServiceCtx context) + { + if (_applicationLaunchProperty == null) + { + return ResultCode.InvalidArgument; + } + + UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + + if (userId.IsNull) + { + return ResultCode.NullArgument; + } + + if (context.Request.SendBuff.Count == 0) + { + return ResultCode.InvalidInputBuffer; + } + + long inputPosition = context.Request.SendBuff[0].Position; + long inputSize = context.Request.SendBuff[0].Size; + + if (inputSize != 0x24000) + { + return ResultCode.InvalidInputBufferSize; + } + + byte[] thumbnailBuffer = context.Memory.ReadBytes(inputPosition, inputSize); + + // TODO: Store thumbnailBuffer somewhere, in save data 0x8000000000000010 ? + + Logger.PrintStub(LogClass.ServiceAcc); + + return ResultCode.Success; + } + + [Command(111)] + // ClearSaveDataThumbnail(nn::account::Uid) + public ResultCode ClearSaveDataThumbnail(ServiceCtx context) + { + if (_applicationLaunchProperty == null) + { + return ResultCode.InvalidArgument; + } + + UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + + if (userId.IsNull) + { + return ResultCode.NullArgument; + } + + // TODO: Clear the Thumbnail somewhere, in save data 0x8000000000000010 ? + + Logger.PrintStub(LogClass.ServiceAcc); + + return ResultCode.Success; + } + + [Command(150)] // 6.0.0+ + // IsUserAccountSwitchLocked() -> bool + public ResultCode IsUserAccountSwitchLocked(ServiceCtx context) + { + // TODO : Validate the following check. + /* + if (_applicationLaunchProperty != null) + { + return ResultCode.ApplicationLaunchPropertyAlreadyInit; + } + */ + + // Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current PID and store the result (NACP File) internally. + // But since we use LibHac and we load one Application at a time, it's not necessary. + + context.ResponseData.Write(context.Device.System.ControlData.UserAccountSwitchLock); + + Logger.PrintStub(LogClass.ServiceAcc); + + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForSystemService.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForSystemService.cs new file mode 100644 index 00000000..f1972f63 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForSystemService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + [Service("acc:u1")] + class IAccountServiceForSystemService : IpcService + { + public IAccountServiceForSystemService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs new file mode 100644 index 00000000..d28ea275 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + [Service("acc:aa")] + class IBaasAccessTokenAccessor : IpcService + { + public IBaasAccessTokenAccessor(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IManagerForApplication.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IManagerForApplication.cs new file mode 100644 index 00000000..aa9e07bd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IManagerForApplication.cs @@ -0,0 +1,40 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Arp; +using Ryujinx.HLE.Utilities; + +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + class IManagerForApplication : IpcService + { + private UInt128 _userId; + private ApplicationLaunchProperty _applicationLaunchProperty; + + public IManagerForApplication(UInt128 userId, ApplicationLaunchProperty applicationLaunchProperty) + { + _userId = userId; + _applicationLaunchProperty = applicationLaunchProperty; + } + + [Command(0)] + // CheckAvailability() + public ResultCode CheckAvailability(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAcc); + + return ResultCode.Success; + } + + [Command(1)] + // GetAccountId() -> nn::account::NetworkServiceAccountId + public ResultCode GetAccountId(ServiceCtx context) + { + long networkServiceAccountId = 0xcafe; + + Logger.PrintStub(LogClass.ServiceAcc, new { networkServiceAccountId }); + + context.ResponseData.Write(networkServiceAccountId); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IProfile.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IProfile.cs new file mode 100644 index 00000000..0470832b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IProfile.cs @@ -0,0 +1,80 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.Utilities; +using System.IO; +using System.Reflection; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + class IProfile : IpcService + { + private UserProfile _profile; + private Stream _profilePictureStream; + + public IProfile(UserProfile profile) + { + _profile = profile; + _profilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg"); + } + + [Command(0)] + // Get() -> (nn::account::profile::ProfileBase, buffer) + public ResultCode Get(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAcc); + + long position = context.Request.ReceiveBuff[0].Position; + + MemoryHelper.FillWithZeros(context.Memory, position, 0x80); + + context.Memory.WriteInt32(position, 0); + context.Memory.WriteInt32(position + 4, 1); + context.Memory.WriteInt64(position + 8, 1); + + return GetBase(context); + } + + [Command(1)] + // GetBase() -> nn::account::profile::ProfileBase + public ResultCode GetBase(ServiceCtx context) + { + _profile.UserId.Write(context.ResponseData); + + context.ResponseData.Write(_profile.LastModifiedTimestamp); + + byte[] username = StringUtils.GetFixedLengthBytes(_profile.Name, 0x20, Encoding.UTF8); + + context.ResponseData.Write(username); + + return ResultCode.Success; + } + + [Command(10)] + // GetImageSize() -> u32 + public ResultCode GetImageSize(ServiceCtx context) + { + context.ResponseData.Write(_profilePictureStream.Length); + + return ResultCode.Success; + } + + [Command(11)] + // LoadImage() -> (u32, buffer) + public ResultCode LoadImage(ServiceCtx context) + { + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferLen = context.Request.ReceiveBuff[0].Size; + + byte[] profilePictureData = new byte[bufferLen]; + + _profilePictureStream.Read(profilePictureData, 0, profilePictureData.Length); + + context.Memory.WriteBytes(bufferPosition, profilePictureData); + + context.ResponseData.Write(_profilePictureStream.Length); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/AccountState.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/AccountState.cs new file mode 100644 index 00000000..2382a255 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/AccountState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + public enum AccountState + { + Closed, + Open + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs new file mode 100644 index 00000000..25004c24 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs @@ -0,0 +1,37 @@ +using Ryujinx.HLE.Utilities; +using System; + +namespace Ryujinx.HLE.HOS.Services.Account.Acc +{ + class UserProfile + { + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public UInt128 UserId { get; private set; } + + public string Name { get; private set; } + + public long LastModifiedTimestamp { get; private set; } + + public AccountState AccountState { get; set; } + public AccountState OnlinePlayState { get; set; } + + public UserProfile(UInt128 userId, string name) + { + UserId = userId; + Name = name; + + LastModifiedTimestamp = 0; + + AccountState = AccountState.Closed; + OnlinePlayState = AccountState.Closed; + + UpdateTimestamp(); + } + + private void UpdateTimestamp() + { + LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/Dauth/IService.cs b/Ryujinx.HLE/HOS/Services/Account/Dauth/IService.cs new file mode 100644 index 00000000..72301349 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/Dauth/IService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Account.Dauth +{ + [Service("dauth:0")] // 5.0.0+ + class IService : IpcService + { + public IService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Account/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Account/ResultCode.cs new file mode 100644 index 00000000..e56732ab --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Account/ResultCode.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.HLE.HOS.Services.Account +{ + enum ResultCode + { + ModuleId = 124, + ErrorCodeShift = 9, + + Success = 0, + + NullArgument = (20 << ErrorCodeShift) | ModuleId, + InvalidArgument = (22 << ErrorCodeShift) | ModuleId, + NullInputBuffer = (30 << ErrorCodeShift) | ModuleId, + InvalidInputBufferSize = (31 << ErrorCodeShift) | ModuleId, + InvalidInputBuffer = (32 << ErrorCodeShift) | ModuleId, + ApplicationLaunchPropertyAlreadyInit = (41 << ErrorCodeShift) | ModuleId, + UserNotFound = (100 << ErrorCodeShift) | ModuleId, + NullObject = (302 << ErrorCodeShift) | ModuleId, + UnknownError1 = (341 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs new file mode 100644 index 00000000..ecd5076f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/ISystemAppletProxy.cs @@ -0,0 +1,99 @@ +using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService +{ + class ISystemAppletProxy : IpcService + { + public ISystemAppletProxy() { } + + [Command(0)] + // GetCommonStateGetter() -> object + public ResultCode GetCommonStateGetter(ServiceCtx context) + { + MakeObject(context, new ICommonStateGetter(context.Device.System)); + + return ResultCode.Success; + } + + [Command(1)] + // GetSelfController() -> object + public ResultCode GetSelfController(ServiceCtx context) + { + MakeObject(context, new ISelfController(context.Device.System)); + + return ResultCode.Success; + } + + [Command(2)] + // GetWindowController() -> object + public ResultCode GetWindowController(ServiceCtx context) + { + MakeObject(context, new IWindowController()); + + return ResultCode.Success; + } + + [Command(3)] + // GetAudioController() -> object + public ResultCode GetAudioController(ServiceCtx context) + { + MakeObject(context, new IAudioController()); + + return ResultCode.Success; + } + + [Command(4)] + // GetDisplayController() -> object + public ResultCode GetDisplayController(ServiceCtx context) + { + MakeObject(context, new IDisplayController()); + + return ResultCode.Success; + } + + [Command(11)] + // GetLibraryAppletCreator() -> object + public ResultCode GetLibraryAppletCreator(ServiceCtx context) + { + MakeObject(context, new ILibraryAppletCreator()); + + return ResultCode.Success; + } + + [Command(20)] + // GetHomeMenuFunctions() -> object + public ResultCode GetHomeMenuFunctions(ServiceCtx context) + { + MakeObject(context, new IHomeMenuFunctions(context.Device.System)); + + return ResultCode.Success; + } + + [Command(21)] + // GetGlobalStateController() -> object + public ResultCode GetGlobalStateController(ServiceCtx context) + { + MakeObject(context, new IGlobalStateController()); + + return ResultCode.Success; + } + + [Command(22)] + // GetApplicationCreator() -> object + public ResultCode GetApplicationCreator(ServiceCtx context) + { + MakeObject(context, new IApplicationCreator()); + + return ResultCode.Success; + } + + [Command(1000)] + // GetDebugFunctions() -> object + public ResultCode GetDebugFunctions(ServiceCtx context) + { + MakeObject(context, new IDebugFunctions()); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs new file mode 100644 index 00000000..9d8e2a96 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs @@ -0,0 +1,73 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage; +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator +{ + class ILibraryAppletAccessor : IpcService + { + private KEvent _stateChangedEvent; + + public ILibraryAppletAccessor(Horizon system) + { + _stateChangedEvent = new KEvent(system); + } + + [Command(0)] + // GetAppletStateChangedEvent() -> handle + public ResultCode GetAppletStateChangedEvent(ServiceCtx context) + { + _stateChangedEvent.ReadableEvent.Signal(); + + if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(10)] + // Start() + public ResultCode Start(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(30)] + // GetResult() + public ResultCode GetResult(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(100)] + // PushInData(object) + public ResultCode PushInData(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(101)] + // PopOutData() -> object + public ResultCode PopOutData(ServiceCtx context) + { + MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams())); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IApplicationCreator.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IApplicationCreator.cs new file mode 100644 index 00000000..79e5b050 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IApplicationCreator.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IApplicationCreator : IpcService + { + public IApplicationCreator() { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAudioController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAudioController.cs new file mode 100644 index 00000000..e630c80d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IAudioController.cs @@ -0,0 +1,66 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IAudioController : IpcService + { + public IAudioController() { } + + [Command(0)] + // SetExpectedMasterVolume(f32, f32) + public ResultCode SetExpectedMasterVolume(ServiceCtx context) + { + float appletVolume = context.RequestData.ReadSingle(); + float libraryAppletVolume = context.RequestData.ReadSingle(); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(1)] + // GetMainAppletExpectedMasterVolume() -> f32 + public ResultCode GetMainAppletExpectedMasterVolume(ServiceCtx context) + { + context.ResponseData.Write(1f); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(2)] + // GetLibraryAppletExpectedMasterVolume() -> f32 + public ResultCode GetLibraryAppletExpectedMasterVolume(ServiceCtx context) + { + context.ResponseData.Write(1f); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(3)] + // ChangeMainAppletMasterVolume(f32, u64) + public ResultCode ChangeMainAppletMasterVolume(ServiceCtx context) + { + float unknown0 = context.RequestData.ReadSingle(); + long unknown1 = context.RequestData.ReadInt64(); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(4)] + // SetTransparentVolumeRate(f32) + public ResultCode SetTransparentVolumeRate(ServiceCtx context) + { + float unknown0 = context.RequestData.ReadSingle(); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs new file mode 100644 index 00000000..085d9fe6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs @@ -0,0 +1,142 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Apm; +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class ICommonStateGetter : IpcService + { + private KEvent _displayResolutionChangeEvent; + + private CpuBoostMode _cpuBoostMode = CpuBoostMode.Disabled; + + public ICommonStateGetter(Horizon system) + { + _displayResolutionChangeEvent = new KEvent(system); + } + + [Command(0)] + // GetEventHandle() -> handle + public ResultCode GetEventHandle(ServiceCtx context) + { + KEvent Event = context.Device.System.AppletState.MessageEvent; + + if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + [Command(1)] + // ReceiveMessage() -> nn::am::AppletMessage + public ResultCode ReceiveMessage(ServiceCtx context) + { + if (!context.Device.System.AppletState.TryDequeueMessage(out MessageInfo message)) + { + return ResultCode.NoMessages; + } + + context.ResponseData.Write((int)message); + + return ResultCode.Success; + } + + [Command(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; + } + + [Command(6)] + // GetPerformanceMode() -> u32 + public ResultCode GetPerformanceMode(ServiceCtx context) + { + PerformanceMode mode = context.Device.System.State.DockedMode + ? PerformanceMode.Docked + : PerformanceMode.Handheld; + + context.ResponseData.Write((int)mode); + + return ResultCode.Success; + } + + [Command(8)] + // GetBootMode() -> u8 + public ResultCode GetBootMode(ServiceCtx context) + { + context.ResponseData.Write((byte)0); //Unknown value. + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(9)] + // GetCurrentFocusState() -> u8 + public ResultCode GetCurrentFocusState(ServiceCtx context) + { + context.ResponseData.Write((byte)context.Device.System.AppletState.FocusState); + + return ResultCode.Success; + } + + [Command(60)] // 3.0.0+ + // GetDefaultDisplayResolution() -> (u32, u32) + public ResultCode GetDefaultDisplayResolution(ServiceCtx context) + { + context.ResponseData.Write(1280); + context.ResponseData.Write(720); + + return ResultCode.Success; + } + + [Command(61)] // 3.0.0+ + // GetDefaultDisplayResolutionChangeEvent() -> handle + public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_displayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(66)] // 6.0.0+ + // SetCpuBoostMode(u32 cpu_boost_mode) + public ResultCode SetCpuBoostMode(ServiceCtx context) + { + uint cpuBoostMode = context.RequestData.ReadUInt32(); + + if (cpuBoostMode > 1) + { + return ResultCode.CpuBoostModeInvalid; + } + + _cpuBoostMode = (CpuBoostMode)cpuBoostMode; + + // NOTE: There is a condition variable after the assignment, probably waiting something with apm:sys service (SetCpuBoostMode call?). + // Since we will probably never support CPU boost things, it's not needed to implement more. + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDebugFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDebugFunctions.cs new file mode 100644 index 00000000..51a112fd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDebugFunctions.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IDebugFunctions : IpcService + { + public IDebugFunctions() { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs new file mode 100644 index 00000000..2b04dbb5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IDisplayController : IpcService + { + public IDisplayController() { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IGlobalStateController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IGlobalStateController.cs new file mode 100644 index 00000000..24eeefb9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IGlobalStateController.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IGlobalStateController : IpcService + { + public IGlobalStateController() { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs new file mode 100644 index 00000000..a5819132 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs @@ -0,0 +1,44 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IHomeMenuFunctions : IpcService + { + private KEvent _channelEvent; + + public IHomeMenuFunctions(Horizon system) + { + // TODO: Signal this Event somewhere in future. + _channelEvent = new KEvent(system); + } + + [Command(10)] + // RequestToGetForeground() + public ResultCode RequestToGetForeground(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(21)] + // GetPopFromGeneralChannelEvent() -> handle + public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs new file mode 100644 index 00000000..8b0b225b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs @@ -0,0 +1,29 @@ +using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class ILibraryAppletCreator : IpcService + { + public ILibraryAppletCreator() { } + + [Command(0)] + // CreateLibraryApplet(u32, u32) -> object + public ResultCode CreateLibraryApplet(ServiceCtx context) + { + MakeObject(context, new ILibraryAppletAccessor(context.Device.System)); + + return ResultCode.Success; + } + + [Command(10)] + // CreateStorage(u64) -> object + public ResultCode CreateStorage(ServiceCtx context) + { + long size = context.RequestData.ReadInt64(); + + MakeObject(context, new IStorage(new byte[size])); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs new file mode 100644 index 00000000..62f1beec --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs @@ -0,0 +1,200 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class ISelfController : IpcService + { + private KEvent _libraryAppletLaunchableEvent; + + private KEvent _accumulatedSuspendedTickChangedEvent; + private int _accumulatedSuspendedTickChangedEventHandle = 0; + + private int _idleTimeDetectionExtension; + + public ISelfController(Horizon system) + { + _libraryAppletLaunchableEvent = new KEvent(system); + } + + [Command(0)] + // Exit() + public ResultCode Exit(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(1)] + // LockExit() + public ResultCode LockExit(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(2)] + // UnlockExit() + public ResultCode UnlockExit(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(9)] + // GetLibraryAppletLaunchableEvent() -> handle + public ResultCode GetLibraryAppletLaunchableEvent(ServiceCtx context) + { + _libraryAppletLaunchableEvent.ReadableEvent.Signal(); + + if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(10)] + // SetScreenShotPermission(u32) + public ResultCode SetScreenShotPermission(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(11)] + // SetOperationModeChangedNotification(b8) + public ResultCode SetOperationModeChangedNotification(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(12)] + // SetPerformanceModeChangedNotification(b8) + public ResultCode SetPerformanceModeChangedNotification(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(13)] + // SetFocusHandlingMode(b8, b8, b8) + public ResultCode SetFocusHandlingMode(ServiceCtx context) + { + bool flag1 = context.RequestData.ReadByte() != 0; + bool flag2 = context.RequestData.ReadByte() != 0; + bool flag3 = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(14)] + // SetRestartMessageEnabled(b8) + public ResultCode SetRestartMessageEnabled(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(16)] // 2.0.0+ + // SetOutOfFocusSuspendingEnabled(b8) + public ResultCode SetOutOfFocusSuspendingEnabled(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(19)] // 3.0.0+ + public ResultCode SetScreenShotImageOrientation(ServiceCtx context) + { + int orientation = context.RequestData.ReadInt32(); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(50)] + // SetHandlesRequestToDisplay(b8) + public ResultCode SetHandlesRequestToDisplay(ServiceCtx context) + { + bool enable = context.RequestData.ReadByte() != 0; + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(62)] + // SetIdleTimeDetectionExtension(u32) + public ResultCode SetIdleTimeDetectionExtension(ServiceCtx context) + { + _idleTimeDetectionExtension = context.RequestData.ReadInt32(); + + Logger.PrintStub(LogClass.ServiceAm, new { _idleTimeDetectionExtension }); + + return ResultCode.Success; + } + + [Command(63)] + // GetIdleTimeDetectionExtension() -> u32 + public ResultCode GetIdleTimeDetectionExtension(ServiceCtx context) + { + context.ResponseData.Write(_idleTimeDetectionExtension); + + Logger.PrintStub(LogClass.ServiceAm, new { _idleTimeDetectionExtension }); + + return ResultCode.Success; + } + + [Command(91)] // 6.0.0+ + // GetAccumulatedSuspendedTickChangedEvent() -> handle + public ResultCode GetAccumulatedSuspendedTickChangedEvent(ServiceCtx context) + { + if (_accumulatedSuspendedTickChangedEventHandle == 0) + { + _accumulatedSuspendedTickChangedEvent = new KEvent(context.Device.System); + + _accumulatedSuspendedTickChangedEvent.ReadableEvent.Signal(); + + if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_accumulatedSuspendedTickChangedEventHandle); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs new file mode 100644 index 00000000..449658cf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IWindowController.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + class IWindowController : IpcService + { + public IWindowController() { } + + [Command(1)] + // GetAppletResourceUserId() -> nn::applet::AppletResourceUserId + public ResultCode GetAppletResourceUserId(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + context.ResponseData.Write(0L); + + return ResultCode.Success; + } + + [Command(10)] + // AcquireForegroundRights() + public ResultCode AcquireForegroundRights(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/FocusState.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/FocusState.cs new file mode 100644 index 00000000..dfd7d7f2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/FocusState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + enum FocusState + { + InFocus = 1, + OutOfFocus = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/MessageInfo.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/MessageInfo.cs new file mode 100644 index 00000000..ff699315 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/MessageInfo.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + enum MessageInfo + { + FocusStateChanged = 0xf, + OperationModeChanged = 0x1e, + PerformanceModeChanged = 0x1f + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/OperationMode.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/OperationMode.cs new file mode 100644 index 00000000..a82ed476 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/Types/OperationMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy +{ + enum OperationMode + { + Handheld = 0, + Docked = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs new file mode 100644 index 00000000..d29a8da4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAllSystemAppletProxiesService.cs @@ -0,0 +1,19 @@ +using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE +{ + [Service("appletAE")] + class IAllSystemAppletProxiesService : IpcService + { + public IAllSystemAppletProxiesService(ServiceCtx context) { } + + [Command(100)] + // OpenSystemAppletProxy(u64, pid, handle) -> object + public ResultCode OpenSystemAppletProxy(ServiceCtx context) + { + MakeObject(context, new ISystemAppletProxy()); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs new file mode 100644 index 00000000..37514275 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs @@ -0,0 +1,21 @@ +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE +{ + class IStorage : IpcService + { + public byte[] Data { get; private set; } + + public IStorage(byte[] data) + { + Data = data; + } + + [Command(0)] + // Open() -> object + public ResultCode Open(ServiceCtx context) + { + MakeObject(context, new IStorageAccessor(this)); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs new file mode 100644 index 00000000..90eb13ce --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs @@ -0,0 +1,76 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE +{ + class IStorageAccessor : IpcService + { + private IStorage _storage; + + public IStorageAccessor(IStorage storage) + { + _storage = storage; + } + + [Command(0)] + // GetSize() -> u64 + public ResultCode GetSize(ServiceCtx context) + { + context.ResponseData.Write((long)_storage.Data.Length); + + return ResultCode.Success; + } + + [Command(10)] + // Write(u64, buffer) + public ResultCode Write(ServiceCtx context) + { + // TODO: Error conditions. + long writePosition = context.RequestData.ReadInt64(); + + (long position, long size) = context.Request.GetBufferType0x21(); + + if (size > 0) + { + long maxSize = _storage.Data.Length - writePosition; + + if (size > maxSize) + { + size = maxSize; + } + + byte[] data = context.Memory.ReadBytes(position, size); + + Buffer.BlockCopy(data, 0, _storage.Data, (int)writePosition, (int)size); + } + + return ResultCode.Success; + } + + [Command(11)] + // Read(u64) -> buffer + public ResultCode Read(ServiceCtx context) + { + // TODO: Error conditions. + long readPosition = context.RequestData.ReadInt64(); + + (long position, long size) = context.Request.GetBufferType0x22(); + + byte[] data; + + if (_storage.Data.Length > size) + { + data = new byte[size]; + + Buffer.BlockCopy(_storage.Data, 0, data, 0, (int)size); + } + else + { + data = _storage.Data; + } + + context.Memory.WriteBytes(position, data); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/Storage/StorageHelper.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Storage/StorageHelper.cs new file mode 100644 index 00000000..9c96221e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/Storage/StorageHelper.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage +{ + class StorageHelper + { + private const uint LaunchParamsMagic = 0xc79497ca; + + public static byte[] MakeLaunchParams() + { + // Size needs to be at least 0x88 bytes otherwise application errors. + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(ms); + + ms.SetLength(0x88); + + writer.Write(LaunchParamsMagic); + writer.Write(1); // IsAccountSelected? Only lower 8 bits actually used. + writer.Write(1L); // User Id Low (note: User Id needs to be != 0) + writer.Write(0L); // User Id High + + return ms.ToArray(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs new file mode 100644 index 00000000..798316be --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -0,0 +1,117 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Am.AppletAE; +using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy +{ + class IApplicationFunctions : IpcService + { + public IApplicationFunctions() { } + + [Command(1)] + // PopLaunchParameter(u32) -> object + public ResultCode PopLaunchParameter(ServiceCtx context) + { + // Only the first 0x18 bytes of the Data seems to be actually used. + MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams())); + + return ResultCode.Success; + } + + [Command(20)] + // EnsureSaveData(nn::account::Uid) -> u64 + public ResultCode EnsureSaveData(ServiceCtx context) + { + long uIdLow = context.RequestData.ReadInt64(); + long uIdHigh = context.RequestData.ReadInt64(); + + Logger.PrintStub(LogClass.ServiceAm); + + context.ResponseData.Write(0L); + + return ResultCode.Success; + } + + [Command(21)] + // GetDesiredLanguage() -> nn::settings::LanguageCode + public ResultCode GetDesiredLanguage(ServiceCtx context) + { + context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode); + + return ResultCode.Success; + } + + [Command(22)] + // SetTerminateResult(u32) + public ResultCode SetTerminateResult(ServiceCtx context) + { + int errorCode = context.RequestData.ReadInt32(); + + string result = GetFormattedErrorCode(errorCode); + + Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{errorCode:x8} ({result})."); + + return ResultCode.Success; + } + + private string GetFormattedErrorCode(int errorCode) + { + int module = (errorCode >> 0) & 0x1ff; + int description = (errorCode >> 9) & 0x1fff; + + return $"{(2000 + module):d4}-{description:d4}"; + } + + [Command(23)] + // GetDisplayVersion() -> nn::oe::DisplayVersion + public ResultCode GetDisplayVersion(ServiceCtx context) + { + // FIXME: Need to check correct version on a switch. + context.ResponseData.Write(1L); + context.ResponseData.Write(0L); + + return ResultCode.Success; + } + + [Command(40)] + // NotifyRunning() -> b8 + public ResultCode NotifyRunning(ServiceCtx context) + { + context.ResponseData.Write(1); + + return ResultCode.Success; + } + + [Command(50)] // 2.0.0+ + // GetPseudoDeviceId() -> nn::util::Uuid + public ResultCode GetPseudoDeviceId(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + context.ResponseData.Write(0L); + context.ResponseData.Write(0L); + + return ResultCode.Success; + } + + [Command(66)] // 3.0.0+ + // InitializeGamePlayRecording(u64, handle) + public ResultCode InitializeGamePlayRecording(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + + [Command(67)] // 3.0.0+ + // SetGamePlayRecordingState(u32) + public ResultCode SetGamePlayRecordingState(ServiceCtx context) + { + int state = context.RequestData.ReadInt32(); + + Logger.PrintStub(LogClass.ServiceAm); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs new file mode 100644 index 00000000..29ee2141 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/IApplicationProxy.cs @@ -0,0 +1,82 @@ +using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy; +using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService +{ + class IApplicationProxy : IpcService + { + public IApplicationProxy() { } + + [Command(0)] + // GetCommonStateGetter() -> object + public ResultCode GetCommonStateGetter(ServiceCtx context) + { + MakeObject(context, new ICommonStateGetter(context.Device.System)); + + return ResultCode.Success; + } + + [Command(1)] + // GetSelfController() -> object + public ResultCode GetSelfController(ServiceCtx context) + { + MakeObject(context, new ISelfController(context.Device.System)); + + return ResultCode.Success; + } + + [Command(2)] + // GetWindowController() -> object + public ResultCode GetWindowController(ServiceCtx context) + { + MakeObject(context, new IWindowController()); + + return ResultCode.Success; + } + + [Command(3)] + // GetAudioController() -> object + public ResultCode GetAudioController(ServiceCtx context) + { + MakeObject(context, new IAudioController()); + + return ResultCode.Success; + } + + [Command(4)] + // GetDisplayController() -> object + public ResultCode GetDisplayController(ServiceCtx context) + { + MakeObject(context, new IDisplayController()); + + return ResultCode.Success; + } + + [Command(11)] + // GetLibraryAppletCreator() -> object + public ResultCode GetLibraryAppletCreator(ServiceCtx context) + { + MakeObject(context, new ILibraryAppletCreator()); + + return ResultCode.Success; + } + + [Command(20)] + // GetApplicationFunctions() -> object + public ResultCode GetApplicationFunctions(ServiceCtx context) + { + MakeObject(context, new IApplicationFunctions()); + + return ResultCode.Success; + } + + [Command(1000)] + // GetDebugFunctions() -> object + public ResultCode GetDebugFunctions(ServiceCtx context) + { + MakeObject(context, new IDebugFunctions()); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs new file mode 100644 index 00000000..fc74aa1f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/IApplicationProxyService.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Services.Am.AppletAE; +using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + [Service("appletOE")] + class IApplicationProxyService : IpcService + { + public IApplicationProxyService(ServiceCtx context) { } + + [Command(0)] + // OpenApplicationProxy(u64, pid, handle) -> object + public ResultCode OpenApplicationProxy(ServiceCtx context) + { + MakeObject(context, new IApplicationProxy()); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/FocusState.cs b/Ryujinx.HLE/HOS/Services/Am/FocusState.cs deleted file mode 100644 index e8ae7223..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/FocusState.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - enum FocusState - { - InFocus = 1, - OutOfFocus = 2 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs deleted file mode 100644 index 0b667347..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - [Service("appletAE")] - class IAllSystemAppletProxiesService : IpcService - { - public IAllSystemAppletProxiesService(ServiceCtx context) { } - - [Command(100)] - // OpenSystemAppletProxy(u64, pid, handle) -> object - public ResultCode OpenSystemAppletProxy(ServiceCtx context) - { - MakeObject(context, new ISystemAppletProxy()); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs deleted file mode 100644 index e4c6615f..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IApplicationCreator : IpcService - { - public IApplicationCreator() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs deleted file mode 100644 index 03e97dfe..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs +++ /dev/null @@ -1,115 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IApplicationFunctions : IpcService - { - public IApplicationFunctions() { } - - [Command(1)] - // PopLaunchParameter(u32) -> object - public ResultCode PopLaunchParameter(ServiceCtx context) - { - // Only the first 0x18 bytes of the Data seems to be actually used. - MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams())); - - return ResultCode.Success; - } - - [Command(20)] - // EnsureSaveData(nn::account::Uid) -> u64 - public ResultCode EnsureSaveData(ServiceCtx context) - { - long uIdLow = context.RequestData.ReadInt64(); - long uIdHigh = context.RequestData.ReadInt64(); - - Logger.PrintStub(LogClass.ServiceAm); - - context.ResponseData.Write(0L); - - return ResultCode.Success; - } - - [Command(21)] - // GetDesiredLanguage() -> nn::settings::LanguageCode - public ResultCode GetDesiredLanguage(ServiceCtx context) - { - context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode); - - return ResultCode.Success; - } - - [Command(22)] - // SetTerminateResult(u32) - public ResultCode SetTerminateResult(ServiceCtx context) - { - int errorCode = context.RequestData.ReadInt32(); - - string result = GetFormattedErrorCode(errorCode); - - Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{errorCode:x8} ({result})."); - - return ResultCode.Success; - } - - private string GetFormattedErrorCode(int errorCode) - { - int module = (errorCode >> 0) & 0x1ff; - int description = (errorCode >> 9) & 0x1fff; - - return $"{(2000 + module):d4}-{description:d4}"; - } - - [Command(23)] - // GetDisplayVersion() -> nn::oe::DisplayVersion - public ResultCode GetDisplayVersion(ServiceCtx context) - { - // FIXME: Need to check correct version on a switch. - context.ResponseData.Write(1L); - context.ResponseData.Write(0L); - - return ResultCode.Success; - } - - [Command(40)] - // NotifyRunning() -> b8 - public ResultCode NotifyRunning(ServiceCtx context) - { - context.ResponseData.Write(1); - - return ResultCode.Success; - } - - [Command(50)] // 2.0.0+ - // GetPseudoDeviceId() -> nn::util::Uuid - public ResultCode GetPseudoDeviceId(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - context.ResponseData.Write(0L); - context.ResponseData.Write(0L); - - return ResultCode.Success; - } - - [Command(66)] // 3.0.0+ - // InitializeGamePlayRecording(u64, handle) - public ResultCode InitializeGamePlayRecording(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(67)] // 3.0.0+ - // SetGamePlayRecordingState(u32) - public ResultCode SetGamePlayRecordingState(ServiceCtx context) - { - int state = context.RequestData.ReadInt32(); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs deleted file mode 100644 index 0e8e3423..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs +++ /dev/null @@ -1,79 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IApplicationProxy : IpcService - { - public IApplicationProxy() { } - - [Command(0)] - // GetCommonStateGetter() -> object - public ResultCode GetCommonStateGetter(ServiceCtx context) - { - MakeObject(context, new ICommonStateGetter(context.Device.System)); - - return ResultCode.Success; - } - - [Command(1)] - // GetSelfController() -> object - public ResultCode GetSelfController(ServiceCtx context) - { - MakeObject(context, new ISelfController(context.Device.System)); - - return ResultCode.Success; - } - - [Command(2)] - // GetWindowController() -> object - public ResultCode GetWindowController(ServiceCtx context) - { - MakeObject(context, new IWindowController()); - - return ResultCode.Success; - } - - [Command(3)] - // GetAudioController() -> object - public ResultCode GetAudioController(ServiceCtx context) - { - MakeObject(context, new IAudioController()); - - return ResultCode.Success; - } - - [Command(4)] - // GetDisplayController() -> object - public ResultCode GetDisplayController(ServiceCtx context) - { - MakeObject(context, new IDisplayController()); - - return ResultCode.Success; - } - - [Command(11)] - // GetLibraryAppletCreator() -> object - public ResultCode GetLibraryAppletCreator(ServiceCtx context) - { - MakeObject(context, new ILibraryAppletCreator()); - - return ResultCode.Success; - } - - [Command(20)] - // GetApplicationFunctions() -> object - public ResultCode GetApplicationFunctions(ServiceCtx context) - { - MakeObject(context, new IApplicationFunctions()); - - return ResultCode.Success; - } - - [Command(1000)] - // GetDebugFunctions() -> object - public ResultCode GetDebugFunctions(ServiceCtx context) - { - MakeObject(context, new IDebugFunctions()); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs deleted file mode 100644 index e0e1e107..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - [Service("appletOE")] - class IApplicationProxyService : IpcService - { - public IApplicationProxyService(ServiceCtx context) { } - - [Command(0)] - // OpenApplicationProxy(u64, pid, handle) -> object - public ResultCode OpenApplicationProxy(ServiceCtx context) - { - MakeObject(context, new IApplicationProxy()); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs b/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs deleted file mode 100644 index f41ed6a0..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IAudioController : IpcService - { - public IAudioController() { } - - [Command(0)] - // SetExpectedMasterVolume(f32, f32) - public ResultCode SetExpectedMasterVolume(ServiceCtx context) - { - float appletVolume = context.RequestData.ReadSingle(); - float libraryAppletVolume = context.RequestData.ReadSingle(); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(1)] - // GetMainAppletExpectedMasterVolume() -> f32 - public ResultCode GetMainAppletExpectedMasterVolume(ServiceCtx context) - { - context.ResponseData.Write(1f); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(2)] - // GetLibraryAppletExpectedMasterVolume() -> f32 - public ResultCode GetLibraryAppletExpectedMasterVolume(ServiceCtx context) - { - context.ResponseData.Write(1f); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(3)] - // ChangeMainAppletMasterVolume(f32, u64) - public ResultCode ChangeMainAppletMasterVolume(ServiceCtx context) - { - float unknown0 = context.RequestData.ReadSingle(); - long unknown1 = context.RequestData.ReadInt64(); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(4)] - // SetTransparentVolumeRate(f32) - public ResultCode SetTransparentVolumeRate(ServiceCtx context) - { - float unknown0 = context.RequestData.ReadSingle(); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs deleted file mode 100644 index 44421b30..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class ICommonStateGetter : IpcService - { - private KEvent _displayResolutionChangeEvent; - - private Apm.CpuBoostMode _cpuBoostMode = Apm.CpuBoostMode.Disabled; - - public ICommonStateGetter(Horizon system) - { - _displayResolutionChangeEvent = new KEvent(system); - } - - [Command(0)] - // GetEventHandle() -> handle - public ResultCode GetEventHandle(ServiceCtx context) - { - KEvent Event = context.Device.System.AppletState.MessageEvent; - - if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - [Command(1)] - // ReceiveMessage() -> nn::am::AppletMessage - public ResultCode ReceiveMessage(ServiceCtx context) - { - if (!context.Device.System.AppletState.TryDequeueMessage(out MessageInfo message)) - { - return ResultCode.NoMessages; - } - - context.ResponseData.Write((int)message); - - return ResultCode.Success; - } - - [Command(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; - } - - [Command(6)] - // GetPerformanceMode() -> u32 - public ResultCode GetPerformanceMode(ServiceCtx context) - { - Apm.PerformanceMode mode = context.Device.System.State.DockedMode - ? Apm.PerformanceMode.Docked - : Apm.PerformanceMode.Handheld; - - context.ResponseData.Write((int)mode); - - return ResultCode.Success; - } - - [Command(8)] - // GetBootMode() -> u8 - public ResultCode GetBootMode(ServiceCtx context) - { - context.ResponseData.Write((byte)0); //Unknown value. - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(9)] - // GetCurrentFocusState() -> u8 - public ResultCode GetCurrentFocusState(ServiceCtx context) - { - context.ResponseData.Write((byte)context.Device.System.AppletState.FocusState); - - return ResultCode.Success; - } - - [Command(60)] // 3.0.0+ - // GetDefaultDisplayResolution() -> (u32, u32) - public ResultCode GetDefaultDisplayResolution(ServiceCtx context) - { - context.ResponseData.Write(1280); - context.ResponseData.Write(720); - - return ResultCode.Success; - } - - [Command(61)] // 3.0.0+ - // GetDefaultDisplayResolutionChangeEvent() -> handle - public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_displayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(66)] // 6.0.0+ - // SetCpuBoostMode(u32 cpu_boost_mode) - public ResultCode SetCpuBoostMode(ServiceCtx context) - { - uint cpuBoostMode = context.RequestData.ReadUInt32(); - - if (cpuBoostMode > 1) - { - return ResultCode.CpuBoostModeInvalid; - } - - _cpuBoostMode = (Apm.CpuBoostMode)cpuBoostMode; - - // NOTE: There is a condition variable after the assignment, probably waiting something with apm:sys service (SetCpuBoostMode call?). - // Since we will probably never support CPU boost things, it's not needed to implement more. - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs deleted file mode 100644 index ebde33f4..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IDebugFunctions : IpcService - { - public IDebugFunctions() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs deleted file mode 100644 index de3313c6..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IDisplayController : IpcService - { - public IDisplayController() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs b/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs deleted file mode 100644 index 9172e094..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IGlobalStateController : IpcService - { - public IGlobalStateController() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs deleted file mode 100644 index 01a68475..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IHomeMenuFunctions : IpcService - { - private KEvent _channelEvent; - - public IHomeMenuFunctions(Horizon system) - { - // TODO: Signal this Event somewhere in future. - _channelEvent = new KEvent(system); - } - - [Command(10)] - // RequestToGetForeground() - public ResultCode RequestToGetForeground(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(21)] - // GetPopFromGeneralChannelEvent() -> handle - public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs deleted file mode 100644 index ec4e23ec..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class ILibraryAppletAccessor : IpcService - { - private KEvent _stateChangedEvent; - - public ILibraryAppletAccessor(Horizon system) - { - _stateChangedEvent = new KEvent(system); - } - - [Command(0)] - // GetAppletStateChangedEvent() -> handle - public ResultCode GetAppletStateChangedEvent(ServiceCtx context) - { - _stateChangedEvent.ReadableEvent.Signal(); - - if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(10)] - // Start() - public ResultCode Start(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(30)] - // GetResult() - public ResultCode GetResult(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(100)] - // PushInData(object) - public ResultCode PushInData(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(101)] - // PopOutData() -> object - public ResultCode PopOutData(ServiceCtx context) - { - MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams())); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs deleted file mode 100644 index 27ae947e..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class ILibraryAppletCreator : IpcService - { - public ILibraryAppletCreator() { } - - [Command(0)] - // CreateLibraryApplet(u32, u32) -> object - public ResultCode CreateLibraryApplet(ServiceCtx context) - { - MakeObject(context, new ILibraryAppletAccessor(context.Device.System)); - - return ResultCode.Success; - } - - [Command(10)] - // CreateStorage(u64) -> object - public ResultCode CreateStorage(ServiceCtx context) - { - long size = context.RequestData.ReadInt64(); - - MakeObject(context, new IStorage(new byte[size])); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs deleted file mode 100644 index b256e59f..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs +++ /dev/null @@ -1,200 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class ISelfController : IpcService - { - private KEvent _libraryAppletLaunchableEvent; - - private KEvent _accumulatedSuspendedTickChangedEvent; - private int _accumulatedSuspendedTickChangedEventHandle = 0; - - private int _idleTimeDetectionExtension; - - public ISelfController(Horizon system) - { - _libraryAppletLaunchableEvent = new KEvent(system); - } - - [Command(0)] - // Exit() - public ResultCode Exit(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(1)] - // LockExit() - public ResultCode LockExit(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(2)] - // UnlockExit() - public ResultCode UnlockExit(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(9)] - // GetLibraryAppletLaunchableEvent() -> handle - public ResultCode GetLibraryAppletLaunchableEvent(ServiceCtx context) - { - _libraryAppletLaunchableEvent.ReadableEvent.Signal(); - - if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(10)] - // SetScreenShotPermission(u32) - public ResultCode SetScreenShotPermission(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(11)] - // SetOperationModeChangedNotification(b8) - public ResultCode SetOperationModeChangedNotification(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(12)] - // SetPerformanceModeChangedNotification(b8) - public ResultCode SetPerformanceModeChangedNotification(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(13)] - // SetFocusHandlingMode(b8, b8, b8) - public ResultCode SetFocusHandlingMode(ServiceCtx context) - { - bool flag1 = context.RequestData.ReadByte() != 0; - bool flag2 = context.RequestData.ReadByte() != 0; - bool flag3 = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(14)] - // SetRestartMessageEnabled(b8) - public ResultCode SetRestartMessageEnabled(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(16)] // 2.0.0+ - // SetOutOfFocusSuspendingEnabled(b8) - public ResultCode SetOutOfFocusSuspendingEnabled(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(19)] // 3.0.0+ - public ResultCode SetScreenShotImageOrientation(ServiceCtx context) - { - int orientation = context.RequestData.ReadInt32(); - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(50)] - // SetHandlesRequestToDisplay(b8) - public ResultCode SetHandlesRequestToDisplay(ServiceCtx context) - { - bool enable = context.RequestData.ReadByte() != 0; - - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - - [Command(62)] - // SetIdleTimeDetectionExtension(u32) - public ResultCode SetIdleTimeDetectionExtension(ServiceCtx context) - { - _idleTimeDetectionExtension = context.RequestData.ReadInt32(); - - Logger.PrintStub(LogClass.ServiceAm, new { _idleTimeDetectionExtension }); - - return ResultCode.Success; - } - - [Command(63)] - // GetIdleTimeDetectionExtension() -> u32 - public ResultCode GetIdleTimeDetectionExtension(ServiceCtx context) - { - context.ResponseData.Write(_idleTimeDetectionExtension); - - Logger.PrintStub(LogClass.ServiceAm, new { _idleTimeDetectionExtension }); - - return ResultCode.Success; - } - - [Command(91)] // 6.0.0+ - // GetAccumulatedSuspendedTickChangedEvent() -> handle - public ResultCode GetAccumulatedSuspendedTickChangedEvent(ServiceCtx context) - { - if (_accumulatedSuspendedTickChangedEventHandle == 0) - { - _accumulatedSuspendedTickChangedEvent = new KEvent(context.Device.System); - - _accumulatedSuspendedTickChangedEvent.ReadableEvent.Signal(); - - if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_accumulatedSuspendedTickChangedEventHandle); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IStorage.cs b/Ryujinx.HLE/HOS/Services/Am/IStorage.cs deleted file mode 100644 index 3d351fc1..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IStorage.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IStorage : IpcService - { - public byte[] Data { get; private set; } - - public IStorage(byte[] data) - { - Data = data; - } - - [Command(0)] - // Open() -> object - public ResultCode Open(ServiceCtx context) - { - MakeObject(context, new IStorageAccessor(this)); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs deleted file mode 100644 index 76f6caf5..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IStorageAccessor : IpcService - { - private IStorage _storage; - - public IStorageAccessor(IStorage storage) - { - _storage = storage; - } - - [Command(0)] - // GetSize() -> u64 - public ResultCode GetSize(ServiceCtx context) - { - context.ResponseData.Write((long)_storage.Data.Length); - - return ResultCode.Success; - } - - [Command(10)] - // Write(u64, buffer) - public ResultCode Write(ServiceCtx context) - { - // TODO: Error conditions. - long writePosition = context.RequestData.ReadInt64(); - - (long position, long size) = context.Request.GetBufferType0x21(); - - if (size > 0) - { - long maxSize = _storage.Data.Length - writePosition; - - if (size > maxSize) - { - size = maxSize; - } - - byte[] data = context.Memory.ReadBytes(position, size); - - Buffer.BlockCopy(data, 0, _storage.Data, (int)writePosition, (int)size); - } - - return ResultCode.Success; - } - - [Command(11)] - // Read(u64) -> buffer - public ResultCode Read(ServiceCtx context) - { - // TODO: Error conditions. - long readPosition = context.RequestData.ReadInt64(); - - (long position, long size) = context.Request.GetBufferType0x22(); - - byte[] data; - - if (_storage.Data.Length > size) - { - data = new byte[size]; - - Buffer.BlockCopy(_storage.Data, 0, data, 0, (int)size); - } - else - { - data = _storage.Data; - } - - context.Memory.WriteBytes(position, data); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs deleted file mode 100644 index 1aa42857..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - class ISystemAppletProxy : IpcService - { - public ISystemAppletProxy() { } - - [Command(0)] - // GetCommonStateGetter() -> object - public ResultCode GetCommonStateGetter(ServiceCtx context) - { - MakeObject(context, new ICommonStateGetter(context.Device.System)); - - return ResultCode.Success; - } - - [Command(1)] - // GetSelfController() -> object - public ResultCode GetSelfController(ServiceCtx context) - { - MakeObject(context, new ISelfController(context.Device.System)); - - return ResultCode.Success; - } - - [Command(2)] - // GetWindowController() -> object - public ResultCode GetWindowController(ServiceCtx context) - { - MakeObject(context, new IWindowController()); - - return ResultCode.Success; - } - - [Command(3)] - // GetAudioController() -> object - public ResultCode GetAudioController(ServiceCtx context) - { - MakeObject(context, new IAudioController()); - - return ResultCode.Success; - } - - [Command(4)] - // GetDisplayController() -> object - public ResultCode GetDisplayController(ServiceCtx context) - { - MakeObject(context, new IDisplayController()); - - return ResultCode.Success; - } - - [Command(11)] - // GetLibraryAppletCreator() -> object - public ResultCode GetLibraryAppletCreator(ServiceCtx context) - { - MakeObject(context, new ILibraryAppletCreator()); - - return ResultCode.Success; - } - - [Command(20)] - // GetHomeMenuFunctions() -> object - public ResultCode GetHomeMenuFunctions(ServiceCtx context) - { - MakeObject(context, new IHomeMenuFunctions(context.Device.System)); - - return ResultCode.Success; - } - - [Command(21)] - // GetGlobalStateController() -> object - public ResultCode GetGlobalStateController(ServiceCtx context) - { - MakeObject(context, new IGlobalStateController()); - - return ResultCode.Success; - } - - [Command(22)] - // GetApplicationCreator() -> object - public ResultCode GetApplicationCreator(ServiceCtx context) - { - MakeObject(context, new IApplicationCreator()); - - return ResultCode.Success; - } - - [Command(1000)] - // GetDebugFunctions() -> object - public ResultCode GetDebugFunctions(ServiceCtx context) - { - MakeObject(context, new IDebugFunctions()); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs b/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs deleted file mode 100644 index 68d0954d..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class IWindowController : IpcService - { - public IWindowController() { } - - [Command(1)] - // GetAppletResourceUserId() -> nn::applet::AppletResourceUserId - public ResultCode GetAppletResourceUserId(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - context.ResponseData.Write(0L); - - return ResultCode.Success; - } - - [Command(10)] - // AcquireForegroundRights() - public ResultCode AcquireForegroundRights(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAm); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/Idle/IPolicyManagerSystem.cs b/Ryujinx.HLE/HOS/Services/Am/Idle/IPolicyManagerSystem.cs new file mode 100644 index 00000000..8c72319c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/Idle/IPolicyManagerSystem.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Idle +{ + [Service("idle:sys")] + class IPolicyManagerSystem : IpcService + { + public IPolicyManagerSystem(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs b/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs deleted file mode 100644 index 65fddbed..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - enum MessageInfo - { - FocusStateChanged = 0xf, - OperationModeChanged = 0x1e, - PerformanceModeChanged = 0x1f - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/Omm/IOperationModeManager.cs b/Ryujinx.HLE/HOS/Services/Am/Omm/IOperationModeManager.cs new file mode 100644 index 00000000..2856e6d7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/Omm/IOperationModeManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Omm +{ + [Service("omm")] + class IOperationModeManager : IpcService + { + public IOperationModeManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs b/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs deleted file mode 100644 index cb11fff9..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Am -{ - enum OperationMode - { - Handheld = 0, - Docked = 1 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/Spsm/IPowerStateInterface.cs b/Ryujinx.HLE/HOS/Services/Am/Spsm/IPowerStateInterface.cs new file mode 100644 index 00000000..a393f76b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/Spsm/IPowerStateInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Spsm +{ + [Service("spsm")] + class IPowerStateInterface : IpcService + { + public IPowerStateInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs b/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs deleted file mode 100644 index a3dbbeb7..00000000 --- a/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.HOS.Services.Am -{ - class StorageHelper - { - private const uint LaunchParamsMagic = 0xc79497ca; - - public static byte[] MakeLaunchParams() - { - // Size needs to be at least 0x88 bytes otherwise application errors. - using (MemoryStream ms = new MemoryStream()) - { - BinaryWriter writer = new BinaryWriter(ms); - - ms.SetLength(0x88); - - writer.Write(LaunchParamsMagic); - writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used. - writer.Write(1L); //User Id Low (note: User Id needs to be != 0) - writer.Write(0L); //User Id High - - return ms.ToArray(); - } - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Am/Tcap/IManager.cs b/Ryujinx.HLE/HOS/Services/Am/Tcap/IManager.cs new file mode 100644 index 00000000..b31ccf8a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/Tcap/IManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Tcap +{ + [Service("tcap")] + class IManager : IpcService + { + public IManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs new file mode 100644 index 00000000..5580c3be --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs @@ -0,0 +1,413 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +using static Ryujinx.HLE.HOS.Services.Android.Parcel; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + class NvFlinger : IDisposable + { + private delegate ResultCode ServiceProcessParcel(ServiceCtx context, BinaryReader parcelReader); + + private Dictionary<(string, int), ServiceProcessParcel> _commands; + + private KEvent _binderEvent; + + private IGalRenderer _renderer; + + private const int BufferQueueCount = 0x40; + private const int BufferQueueMask = BufferQueueCount - 1; + + private BufferEntry[] _bufferQueue; + + private AutoResetEvent _waitBufferFree; + + private bool _disposed; + + public NvFlinger(IGalRenderer renderer, KEvent binderEvent) + { + _commands = new Dictionary<(string, int), ServiceProcessParcel> + { + { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, + { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, + { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, + { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } + }; + + _renderer = renderer; + _binderEvent = binderEvent; + + _bufferQueue = new BufferEntry[0x40]; + + _waitBufferFree = new AutoResetEvent(false); + } + + public ResultCode ProcessParcelRequest(ServiceCtx context, byte[] parcelData, int code) + { + using (MemoryStream ms = new MemoryStream(parcelData)) + { + BinaryReader reader = new BinaryReader(ms); + + ms.Seek(4, SeekOrigin.Current); + + int strSize = reader.ReadInt32(); + + string interfaceName = Encoding.Unicode.GetString(reader.ReadBytes(strSize * 2)); + + long remainder = ms.Position & 0xf; + + if (remainder != 0) + { + ms.Seek(0x10 - remainder, SeekOrigin.Current); + } + + ms.Seek(0x50, SeekOrigin.Begin); + + if (_commands.TryGetValue((interfaceName, code), out ServiceProcessParcel procReq)) + { + Logger.PrintDebug(LogClass.ServiceVi, $"{interfaceName} {procReq.Method.Name}"); + + return procReq(context, reader); + } + else + { + throw new NotImplementedException($"{interfaceName} {code}"); + } + } + } + + private ResultCode GbpRequestBuffer(ServiceCtx context, BinaryReader parcelReader) + { + int slot = parcelReader.ReadInt32(); + + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(ms); + + BufferEntry entry = _bufferQueue[slot]; + + int bufferCount = 1; //? + long bufferSize = entry.Data.Size; + + writer.Write(bufferCount); + writer.Write(bufferSize); + + entry.Data.Write(writer); + + writer.Write(0); + + return MakeReplyParcel(context, ms.ToArray()); + } + } + + private ResultCode GbpDequeueBuffer(ServiceCtx context, BinaryReader parcelReader) + { + // TODO: Errors. + int format = parcelReader.ReadInt32(); + int width = parcelReader.ReadInt32(); + int height = parcelReader.ReadInt32(); + int getTimestamps = parcelReader.ReadInt32(); + int usage = parcelReader.ReadInt32(); + + int slot = GetFreeSlotBlocking(width, height); + + return MakeReplyParcel(context, slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + private ResultCode GbpQueueBuffer(ServiceCtx context, BinaryReader parcelReader) + { + context.Device.Statistics.RecordGameFrameTime(); + + // TODO: Errors. + int slot = parcelReader.ReadInt32(); + + long Position = parcelReader.BaseStream.Position; + + QueueBufferObject queueBufferObject = ReadFlattenedObject(parcelReader); + + parcelReader.BaseStream.Position = Position; + + _bufferQueue[slot].Transform = queueBufferObject.Transform; + _bufferQueue[slot].Crop = queueBufferObject.Crop; + + _bufferQueue[slot].State = BufferState.Queued; + + SendFrameBuffer(context, slot); + + if (context.Device.EnableDeviceVsync) + { + context.Device.VsyncEvent.WaitOne(); + } + + return MakeReplyParcel(context, 1280, 720, 0, 0, 0); + } + + private ResultCode GbpDetachBuffer(ServiceCtx context, BinaryReader parcelReader) + { + return MakeReplyParcel(context, 0); + } + + private ResultCode GbpCancelBuffer(ServiceCtx context, BinaryReader parcelReader) + { + // TODO: Errors. + int slot = parcelReader.ReadInt32(); + + MultiFence fence = ReadFlattenedObject(parcelReader); + + _bufferQueue[slot].State = BufferState.Free; + + _waitBufferFree.Set(); + + return MakeReplyParcel(context, 0); + } + + private ResultCode GbpQuery(ServiceCtx context, BinaryReader parcelReader) + { + return MakeReplyParcel(context, 0, 0); + } + + private ResultCode GbpConnect(ServiceCtx context, BinaryReader parcelReader) + { + return MakeReplyParcel(context, 1280, 720, 0, 0, 0); + } + + private ResultCode GbpDisconnect(ServiceCtx context, BinaryReader parcelReader) + { + return MakeReplyParcel(context, 0); + } + + private ResultCode GbpPreallocBuffer(ServiceCtx context, BinaryReader parcelReader) + { + int slot = parcelReader.ReadInt32(); + + bool hasInput = parcelReader.ReadInt32() == 1; + + if (hasInput) + { + byte[] graphicBuffer = ReadFlattenedObject(parcelReader); + + _bufferQueue[slot].State = BufferState.Free; + + using (BinaryReader graphicBufferReader = new BinaryReader(new MemoryStream(graphicBuffer))) + { + _bufferQueue[slot].Data = new GbpBuffer(graphicBufferReader); + } + + } + + return MakeReplyParcel(context, 0); + } + + private byte[] ReadFlattenedObject(BinaryReader reader) + { + long flattenedObjectSize = reader.ReadInt64(); + + return reader.ReadBytes((int)flattenedObjectSize); + } + + private unsafe T ReadFlattenedObject(BinaryReader reader) where T: struct + { + byte[] data = ReadFlattenedObject(reader); + + fixed (byte* ptr = data) + { + return Marshal.PtrToStructure((IntPtr)ptr); + } + } + + private ResultCode MakeReplyParcel(ServiceCtx context, params int[] ints) + { + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(ms); + + foreach (int Int in ints) + { + writer.Write(Int); + } + + return MakeReplyParcel(context, ms.ToArray()); + } + } + + private ResultCode MakeReplyParcel(ServiceCtx context, byte[] data) + { + (long replyPos, long replySize) = context.Request.GetBufferType0x22(); + + byte[] reply = MakeParcel(data, new byte[0]); + + context.Memory.WriteBytes(replyPos, reply); + + return ResultCode.Success; + } + + private GalImageFormat ConvertColorFormat(ColorFormat colorFormat) + { + switch (colorFormat) + { + case ColorFormat.A8B8G8R8: + return GalImageFormat.Rgba8 | GalImageFormat.Unorm; + case ColorFormat.X8B8G8R8: + return GalImageFormat.Rgbx8 | GalImageFormat.Unorm; + case ColorFormat.R5G6B5: + return GalImageFormat.Bgr565 | GalImageFormat.Unorm; + case ColorFormat.A8R8G8B8: + return GalImageFormat.Bgra8 | GalImageFormat.Unorm; + case ColorFormat.A4B4G4R4: + return GalImageFormat.Rgba4 | GalImageFormat.Unorm; + default: + throw new NotImplementedException($"Color Format \"{colorFormat}\" not implemented!"); + } + } + + // TODO: support multi surface + private void SendFrameBuffer(ServiceCtx context, int slot) + { + int fbWidth = _bufferQueue[slot].Data.Header.Width; + int fbHeight = _bufferQueue[slot].Data.Header.Height; + + int nvMapHandle = _bufferQueue[slot].Data.Buffer.Surfaces[0].NvMapHandle; + + if (nvMapHandle == 0) + { + nvMapHandle = _bufferQueue[slot].Data.Buffer.NvMapId; + } + + int bufferOffset = _bufferQueue[slot].Data.Buffer.Surfaces[0].Offset; + + NvMapHandle map = NvMapIoctl.GetNvMap(context, nvMapHandle); + + long fbAddr = map.Address + bufferOffset; + + _bufferQueue[slot].State = BufferState.Acquired; + + Rect crop = _bufferQueue[slot].Crop; + + bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX); + bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY); + + GalImageFormat imageFormat = ConvertColorFormat(_bufferQueue[slot].Data.Buffer.Surfaces[0].ColorFormat); + + int BlockHeight = 1 << _bufferQueue[slot].Data.Buffer.Surfaces[0].BlockHeightLog2; + + // Note: Rotation is being ignored. + + int top = crop.Top; + int left = crop.Left; + int right = crop.Right; + int bottom = crop.Bottom; + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + _renderer.QueueAction(() => + { + if (!_renderer.Texture.TryGetImage(fbAddr, out GalImage image)) + { + image = new GalImage( + fbWidth, + fbHeight, 1, 1, 1, BlockHeight, 1, + GalMemoryLayout.BlockLinear, + imageFormat, + GalTextureTarget.TwoD); + } + + context.Device.Gpu.ResourceManager.ClearPbCache(); + context.Device.Gpu.ResourceManager.SendTexture(vmm, fbAddr, image); + + _renderer.RenderTarget.SetTransform(flipX, flipY, top, left, right, bottom); + _renderer.RenderTarget.Present(fbAddr); + + ReleaseBuffer(slot); + }); + } + + private void ReleaseBuffer(int slot) + { + _bufferQueue[slot].State = BufferState.Free; + + _binderEvent.ReadableEvent.Signal(); + + _waitBufferFree.Set(); + } + + private int GetFreeSlotBlocking(int width, int height) + { + int slot; + + do + { + if ((slot = GetFreeSlot(width, height)) != -1) + { + break; + } + + if (_disposed) + { + break; + } + + _waitBufferFree.WaitOne(); + } + while (!_disposed); + + return slot; + } + + private int GetFreeSlot(int width, int height) + { + lock (_bufferQueue) + { + for (int slot = 0; slot < _bufferQueue.Length; slot++) + { + if (_bufferQueue[slot].State != BufferState.Free) + { + continue; + } + + GbpBuffer data = _bufferQueue[slot].Data; + + if (data.Header.Width == width && + data.Header.Height == height) + { + _bufferQueue[slot].State = BufferState.Dequeued; + + return slot; + } + } + } + + return -1; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && !_disposed) + { + _disposed = true; + + _waitBufferFree.Set(); + _waitBufferFree.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Parcel.cs b/Ryujinx.HLE/HOS/Services/Android/Parcel.cs new file mode 100644 index 00000000..63c5a82f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Parcel.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + static class Parcel + { + public static byte[] GetParcelData(byte[] parcel) + { + if (parcel == null) + { + throw new ArgumentNullException(nameof(parcel)); + } + + using (MemoryStream ms = new MemoryStream(parcel)) + { + BinaryReader reader = new BinaryReader(ms); + + int dataSize = reader.ReadInt32(); + int dataOffset = reader.ReadInt32(); + int objsSize = reader.ReadInt32(); + int objsOffset = reader.ReadInt32(); + + ms.Seek(dataOffset - 0x10, SeekOrigin.Current); + + return reader.ReadBytes(dataSize); + } + } + + public static byte[] MakeParcel(byte[] data, byte[] objs) + { + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + if (objs == null) + { + throw new ArgumentNullException(nameof(objs)); + } + + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(ms); + + writer.Write(data.Length); + writer.Write(0x10); + writer.Write(objs.Length); + writer.Write(data.Length + 0x10); + + writer.Write(data); + writer.Write(objs); + + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/BufferEntry.cs b/Ryujinx.HLE/HOS/Services/Android/Types/BufferEntry.cs new file mode 100644 index 00000000..91744859 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/BufferEntry.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + struct BufferEntry + { + public BufferState State; + + public HalTransform Transform; + + public Rect Crop; + + public GbpBuffer Data; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/BufferState.cs b/Ryujinx.HLE/HOS/Services/Android/Types/BufferState.cs new file mode 100644 index 00000000..e79d5d8f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/BufferState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum BufferState + { + Free, + Dequeued, + Queued, + Acquired + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorBytePerPixel.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorBytePerPixel.cs new file mode 100644 index 00000000..a937f15f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorBytePerPixel.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorBytePerPixel + { + Bpp1 = 1, + Bpp2 = 2, + Bpp4 = 4, + Bpp8 = 8, + Bpp16 = 16, + Bpp24 = 24, + Bpp32 = 32, + Bpp48 = 48, + Bpp64 = 64, + Bpp96 = 96, + Bpp128 = 128 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorComponent.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorComponent.cs new file mode 100644 index 00000000..7ea20df7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorComponent.cs @@ -0,0 +1,42 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorComponent : uint + { + X1 = (0x01 << ColorShift.Component) | ColorBytePerPixel.Bpp1, + X2 = (0x02 << ColorShift.Component) | ColorBytePerPixel.Bpp2, + X4 = (0x03 << ColorShift.Component) | ColorBytePerPixel.Bpp4, + X8 = (0x04 << ColorShift.Component) | ColorBytePerPixel.Bpp8, + Y4X4 = (0x05 << ColorShift.Component) | ColorBytePerPixel.Bpp8, + X3Y3Z2 = (0x06 << ColorShift.Component) | ColorBytePerPixel.Bpp8, + X8Y8 = (0x07 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X8Y8X8Z8 = (0x08 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Y8X8Z8X8 = (0x09 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X16 = (0x0A << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Y2X14 = (0x0B << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Y4X12 = (0x0C << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Y6X10 = (0x0D << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Y8X8 = (0x0E << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X10 = (0x0F << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X12 = (0x10 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + Z5Y5X6 = (0x11 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X5Y6Z5 = (0x12 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X6Y5Z5 = (0x13 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X1Y5Z5W5 = (0x14 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X4Y4Z4W4 = (0x15 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X5Y1Z5W5 = (0x16 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X5Y5Z1W5 = (0x17 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X5Y5Z5W1 = (0x18 << ColorShift.Component) | ColorBytePerPixel.Bpp16, + X8Y8Z8 = (0x19 << ColorShift.Component) | ColorBytePerPixel.Bpp24, + X24 = (0x1A << ColorShift.Component) | ColorBytePerPixel.Bpp24, + X32 = (0x1C << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X16Y16 = (0x1D << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X11Y11Z10 = (0x1E << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X2Y10Z10W10 = (0x20 << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X8Y8Z8W8 = (0x21 << ColorShift.Component) | ColorBytePerPixel.Bpp32, + Y10X10 = (0x22 << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X10Y10Z10W2 = (0x23 << ColorShift.Component) | ColorBytePerPixel.Bpp32, + Y12X12 = (0x24 << ColorShift.Component) | ColorBytePerPixel.Bpp32, + X20Y20Z20 = (0x26 << ColorShift.Component) | ColorBytePerPixel.Bpp64, + X16Y16Z16W16 = (0x27 << ColorShift.Component) | ColorBytePerPixel.Bpp64, + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorDataType.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorDataType.cs new file mode 100644 index 00000000..c380cb1b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorDataType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorDataType + { + Integer = 0x0 << ColorShift.DataType, + Float = 0x1 << ColorShift.DataType, + Stencil = 0x2 << ColorShift.DataType + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorFormat.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorFormat.cs new file mode 100644 index 00000000..1aed4d58 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorFormat.cs @@ -0,0 +1,235 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorFormat : ulong + { + NonColor8 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + NonColor16 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + NonColor24 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X24 | ColorDataType.Integer, + NonColor32 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X32 | ColorDataType.Integer, + X4C4 = ColorSpace.NonColor | ColorSwizzle.Y000 | ColorComponent.Y4X4 | ColorDataType.Integer, + A4L4 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y4X4 | ColorDataType.Integer, + A8L8 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y8X8 | ColorDataType.Integer, + Float_A16L16 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.X16Y16 | ColorDataType.Float, + A1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + A4B4G4R4 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + A5B5G5R1 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + A2B10G10R10 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + A4R4G4B4 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + A5R1G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X5Y1Z5W5 | ColorDataType.Integer, + A2R10G10B10 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A1 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X1 | ColorDataType.Integer, + A2 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X2 | ColorDataType.Integer, + A4 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X4 | ColorDataType.Integer, + A8 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X8 | ColorDataType.Integer, + A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Integer, + A32 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X32 | ColorDataType.Integer, + Float_A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Float, + L4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y4X4 | ColorDataType.Integer, + L8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y8X8 | ColorDataType.Integer, + B4G4R4A4 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + B5G5R1A5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z1W5 | ColorDataType.Integer, + B5G5R5A1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + B8G8R8A8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + B10G10R10A2 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R1G5B5A5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + R4G4B4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + R5G5B5A1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + R8G8B8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + R10G10B10A2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + L1 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X1 | ColorDataType.Integer, + L2 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X2 | ColorDataType.Integer, + L4 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X4 | ColorDataType.Integer, + L8 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X8 | ColorDataType.Integer, + L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Integer, + L32 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X32 | ColorDataType.Integer, + Float_L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Float, + B5G6R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, + B6G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X6Y5Z5 | ColorDataType.Integer, + B5G5R5X1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + B8_G8_R8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + B8G8R8X8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + Float_B10G11R11 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X11Y11Z10 | ColorDataType.Float, + X1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + X8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + R3G3B2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X3Y3Z2 | ColorDataType.Integer, + R5G5B6 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.Z5Y5X6 | ColorDataType.Integer, + R5G6B5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, + R5G5B5X1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + R8_G8_B8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + R8G8B8X8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + X8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + RG8 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.Y8X8 | ColorDataType.Integer, + R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Integer, + Float_R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Float, + R8 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X8 | ColorDataType.Integer, + R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Integer, + Float_R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Float, + A2B10G10R10_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_sRGB = ColorSpace.SRGB | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_709 = ColorSpace.RGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_709 = ColorSpace.RGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_709 = ColorSpace.RGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_scRGB_Linear = ColorSpace.LinearScRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A2B10G10R10_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_2020 = ColorSpace.RGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A2R10G10B10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_2020_PQ = ColorSpace.RGB2020_PQ | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A4I4 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y4X4 | ColorDataType.Integer, + A8I8 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y8X8 | ColorDataType.Integer, + I4A4 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y4X4 | ColorDataType.Integer, + I8A8 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y8X8 | ColorDataType.Integer, + I1 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X1 | ColorDataType.Integer, + I2 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X2 | ColorDataType.Integer, + I4 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X4 | ColorDataType.Integer, + I8 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + A8Y8U8V8 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16Y16U16V16 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Y8U8V8A8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + V8_U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + YVYU = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, + VYUY = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, + UYVY = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, + YUYV = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, + Y8_U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + V8_U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + U8_V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + Y8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + V8_U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + U8_V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + Y8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + V8_U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + V8_U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + V10U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U10V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + Bayer8RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + XYZ = ColorSpace.XYZ | ColorSwizzle.XYZ1 | ColorComponent.X20Y20Z20 | ColorDataType.Float, + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorShift.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorShift.cs new file mode 100644 index 00000000..827e0445 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorShift.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + class ColorShift + { + public const int Swizzle = 16; + public const int DataType = 14; + public const int Space = 32; + public const int Component = 8; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSpace.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSpace.cs new file mode 100644 index 00000000..6ee6f428 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSpace.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorSpace : ulong + { + NonColor = 0x0L << ColorShift.Space, + LinearRGBA = 0x1L << ColorShift.Space, + SRGB = 0x2L << ColorShift.Space, + + RGB709 = 0x3L << ColorShift.Space, + LinearRGB709 = 0x4L << ColorShift.Space, + + LinearScRGB = 0x5L << ColorShift.Space, + + RGB2020 = 0x6L << ColorShift.Space, + LinearRGB2020 = 0x7L << ColorShift.Space, + RGB2020_PQ = 0x8L << ColorShift.Space, + + ColorIndex = 0x9L << ColorShift.Space, + + YCbCr601 = 0xAL << ColorShift.Space, + YCbCr601_RR = 0xBL << ColorShift.Space, + YCbCr601_ER = 0xCL << ColorShift.Space, + YCbCr709 = 0xDL << ColorShift.Space, + YCbCr709_ER = 0xEL << ColorShift.Space, + + BayerRGGB = 0x10L << ColorShift.Space, + BayerBGGR = 0x11L << ColorShift.Space, + BayerGRBG = 0x12L << ColorShift.Space, + BayerGBRG = 0x13L << ColorShift.Space, + + XYZ = 0x14L << ColorShift.Space, + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSwizzle.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSwizzle.cs new file mode 100644 index 00000000..f82d5a56 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Color/ColorSwizzle.cs @@ -0,0 +1,31 @@ +namespace Ryujinx.HLE.HOS.Services.Android +{ + enum ColorSwizzle + { + XYZW = 0x688 << ColorShift.Swizzle, + ZYXW = 0x60a << ColorShift.Swizzle, + WZYX = 0x053 << ColorShift.Swizzle, + YZWX = 0x0d1 << ColorShift.Swizzle, + XYZ1 = 0xa88 << ColorShift.Swizzle, + YZW1 = 0xad1 << ColorShift.Swizzle, + XXX1 = 0xa00 << ColorShift.Swizzle, + XZY1 = 0xa50 << ColorShift.Swizzle, + ZYX1 = 0xa0a << ColorShift.Swizzle, + WZY1 = 0xa53 << ColorShift.Swizzle, + X000 = 0x920 << ColorShift.Swizzle, + Y000 = 0x921 << ColorShift.Swizzle, + XY01 = 0xb08 << ColorShift.Swizzle, + X001 = 0xb20 << ColorShift.Swizzle, + X00X = 0x121 << ColorShift.Swizzle, + X00Y = 0x320 << ColorShift.Swizzle, + _0YX0 = 0x80c << ColorShift.Swizzle, + _0ZY0 = 0x814 << ColorShift.Swizzle, + _0XZ0 = 0x884 << ColorShift.Swizzle, + _0X00 = 0x904 << ColorShift.Swizzle, + _00X0 = 0x824 << ColorShift.Swizzle, + _000X = 0x124 << ColorShift.Swizzle, + _0XY0 = 0x844 << ColorShift.Swizzle, + XXXY = 0x200 << ColorShift.Swizzle, + YYYX = 0x049 << ColorShift.Swizzle + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Fence.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Fence.cs new file mode 100644 index 00000000..a09b7948 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Fence.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8)] + struct Fence + { + public int Id; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/GbpBuffer.cs b/Ryujinx.HLE/HOS/Services/Android/Types/GbpBuffer.cs new file mode 100644 index 00000000..766806f0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/GbpBuffer.cs @@ -0,0 +1,37 @@ +using Ryujinx.Common; +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + struct GbpBuffer + { + public GraphicBufferHeader Header { get; private set; } + public NvGraphicBuffer Buffer { get; private set; } + + public int Size => Marshal.SizeOf() + Marshal.SizeOf(); + + public GbpBuffer(BinaryReader reader) + { + Header = reader.ReadStruct(); + + // ignore fds + // TODO: check if that is used in official implementation + reader.BaseStream.Position += Header.FdsCount * 4; + + if (Header.IntsCount != 0x51) + { + throw new NotImplementedException($"Unexpected Graphic Buffer ints count (expected 0x51, found 0x{Header.IntsCount:x}"); + } + + Buffer = reader.ReadStruct(); + } + + public void Write(BinaryWriter writer) + { + writer.WriteStruct(Header); + writer.WriteStruct(Buffer); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/GraphicBufferHeader.cs b/Ryujinx.HLE/HOS/Services/Android/Types/GraphicBufferHeader.cs new file mode 100644 index 00000000..d82523db --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/GraphicBufferHeader.cs @@ -0,0 +1,21 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Sequential, Size = 0x28)] + struct GraphicBufferHeader + { + public int Magic; + public int Width; + public int Height; + public int Stride; + public int Format; + public int Usage; + + public int Pid; + public int RefCount; + + public int FdsCount; + public int IntsCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/HalTransform.cs b/Ryujinx.HLE/HOS/Services/Android/Types/HalTransform.cs new file mode 100644 index 00000000..fd271063 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/HalTransform.cs @@ -0,0 +1,14 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [Flags] + enum HalTransform + { + FlipX = 1, + FlipY = 2, + Rotate90 = 4, + Rotate180 = FlipX | FlipY, + Rotate270 = Rotate90 | Rotate180 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/MultiFence.cs b/Ryujinx.HLE/HOS/Services/Android/Types/MultiFence.cs new file mode 100644 index 00000000..a50eea89 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/MultiFence.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Explicit, Size = 0x24)] + struct MultiFence + { + [FieldOffset(0x0)] + public int FenceCount; + + [FieldOffset(0x4)] + public Fence Fence0; + + [FieldOffset(0xC)] + public Fence Fence1; + + [FieldOffset(0x14)] + public Fence Fence2; + + [FieldOffset(0x1C)] + public Fence Fence3; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBuffer.cs b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBuffer.cs new file mode 100644 index 00000000..90c44997 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBuffer.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Explicit, Size = 0x144)] + struct NvGraphicBuffer + { + [FieldOffset(0x4)] + public int NvMapId; + + [FieldOffset(0xC)] + public int Magic; + + [FieldOffset(0x10)] + public int Pid; + + [FieldOffset(0x14)] + public int Type; + + [FieldOffset(0x18)] + public int Usage; + + [FieldOffset(0x1C)] + public int PixelFormat; + + [FieldOffset(0x20)] + public int ExternalPixelFormat; + + [FieldOffset(0x24)] + public int Stride; + + [FieldOffset(0x28)] + public int FrameBufferSize; + + [FieldOffset(0x2C)] + public int PlanesCount; + + [FieldOffset(0x34)] + public NvGraphicBufferSurfaceArray Surfaces; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurface.cs b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurface.cs new file mode 100644 index 00000000..d5dd682c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurface.cs @@ -0,0 +1,44 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Explicit, Size = 0x58)] + struct NvGraphicBufferSurface + { + [FieldOffset(0)] + public uint Width; + + [FieldOffset(0x4)] + public uint Height; + + [FieldOffset(0x8)] + public ColorFormat ColorFormat; + + [FieldOffset(0x10)] + public int Layout; + + [FieldOffset(0x14)] + public int Pitch; + + [FieldOffset(0x18)] + public int NvMapHandle; + + [FieldOffset(0x1C)] + public int Offset; + + [FieldOffset(0x20)] + public int Kind; + + [FieldOffset(0x24)] + public int BlockHeightLog2; + + [FieldOffset(0x28)] + public int ScanFormat; + + [FieldOffset(0x30)] + public long Flags; + + [FieldOffset(0x38)] + public long Size; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurfaceArray.cs b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurfaceArray.cs new file mode 100644 index 00000000..be2855ff --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/NvGraphicBufferSurfaceArray.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Explicit)] + struct NvGraphicBufferSurfaceArray + { + [FieldOffset(0x0)] + private NvGraphicBufferSurface Surface0; + + [FieldOffset(0x58)] + private NvGraphicBufferSurface Surface1; + + [FieldOffset(0xb0)] + private NvGraphicBufferSurface Surface2; + + public NvGraphicBufferSurface this[int index] + { + get + { + if (index == 0) + { + return Surface0; + } + else if (index == 1) + { + return Surface1; + } + else if (index == 2) + { + return Surface2; + } + + throw new IndexOutOfRangeException(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/QueueBufferObject.cs b/Ryujinx.HLE/HOS/Services/Android/Types/QueueBufferObject.cs new file mode 100644 index 00000000..4112da07 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/QueueBufferObject.cs @@ -0,0 +1,35 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Explicit)] + struct QueueBufferObject + { + [FieldOffset(0x0)] + public long Timestamp; + + [FieldOffset(0x8)] + public int IsAutoTimestamp; + + [FieldOffset(0xC)] + public Rect Crop; + + [FieldOffset(0x1C)] + public int ScalingMode; + + [FieldOffset(0x20)] + public HalTransform Transform; + + [FieldOffset(0x24)] + public int StickyTransform; + + [FieldOffset(0x28)] + public int Unknown; + + [FieldOffset(0x2C)] + public int SwapInterval; + + [FieldOffset(0x30)] + public MultiFence Fence; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Android/Types/Rect.cs b/Ryujinx.HLE/HOS/Services/Android/Types/Rect.cs new file mode 100644 index 00000000..abe81abd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Android/Types/Rect.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + struct Rect + { + public int Top; + public int Left; + public int Right; + public int Bottom; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/CpuBoostMode.cs b/Ryujinx.HLE/HOS/Services/Apm/CpuBoostMode.cs deleted file mode 100644 index a4c87d3c..00000000 --- a/Ryujinx.HLE/HOS/Services/Apm/CpuBoostMode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Apm -{ - enum CpuBoostMode - { - Disabled = 0, - Mode1 = 1, // Use PerformanceConfiguration13 and PerformanceConfiguration14, or PerformanceConfiguration15 and PerformanceConfiguration16 - Mode2 = 2 // Use PerformanceConfiguration15 and PerformanceConfiguration16. - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/IManager.cs b/Ryujinx.HLE/HOS/Services/Apm/IManager.cs index 1458ac58..19fbcd44 100644 --- a/Ryujinx.HLE/HOS/Services/Apm/IManager.cs +++ b/Ryujinx.HLE/HOS/Services/Apm/IManager.cs @@ -1,7 +1,6 @@ namespace Ryujinx.HLE.HOS.Services.Apm { - [Service("apm")] - [Service("apm:p")] + [Service("apm")] // 8.0.0+ class IManager : IpcService { public IManager(ServiceCtx context) { } diff --git a/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs b/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs deleted file mode 100644 index e42edebc..00000000 --- a/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Apm -{ - enum PerformanceConfiguration : uint // Clocks are all in MHz. - { // CPU | GPU | RAM | NOTE - PerformanceConfiguration1 = 0x00010000, // 1020 | 384 | 1600 | Only available while docked. - PerformanceConfiguration2 = 0x00010001, // 1020 | 768 | 1600 | Only available while docked. - PerformanceConfiguration3 = 0x00010002, // 1224 | 691.2 | 1600 | Only available for SDEV units. - PerformanceConfiguration4 = 0x00020000, // 1020 | 230.4 | 1600 | Only available for SDEV units. - PerformanceConfiguration5 = 0x00020001, // 1020 | 307.2 | 1600 | - PerformanceConfiguration6 = 0x00020002, // 1224 | 230.4 | 1600 | - PerformanceConfiguration7 = 0x00020003, // 1020 | 307 | 1331.2 | - PerformanceConfiguration8 = 0x00020004, // 1020 | 384 | 1331.2 | - PerformanceConfiguration9 = 0x00020005, // 1020 | 307.2 | 1065.6 | - PerformanceConfiguration10 = 0x00020006, // 1020 | 384 | 1065.6 | - PerformanceConfiguration11 = 0x92220007, // 1020 | 460.8 | 1600 | - PerformanceConfiguration12 = 0x92220008, // 1020 | 460.8 | 1331.2 | - PerformanceConfiguration13 = 0x92220009, // 1785 | 768 | 1600 | 7.0.0+ - PerformanceConfiguration14 = 0x9222000A, // 1785 | 768 | 1331.2 | 7.0.0+ - PerformanceConfiguration15 = 0x9222000B, // 1020 | 768 | 1600 | 7.0.0+ - PerformanceConfiguration16 = 0x9222000C // 1020 | 768 | 1331.2 | 7.0.0+ - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs b/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs deleted file mode 100644 index a7a0dfad..00000000 --- a/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Apm -{ - enum PerformanceMode - { - Handheld = 0, - Docked = 1 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/Types/CpuBoostMode.cs b/Ryujinx.HLE/HOS/Services/Apm/Types/CpuBoostMode.cs new file mode 100644 index 00000000..a4c87d3c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/Types/CpuBoostMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Apm +{ + enum CpuBoostMode + { + Disabled = 0, + Mode1 = 1, // Use PerformanceConfiguration13 and PerformanceConfiguration14, or PerformanceConfiguration15 and PerformanceConfiguration16 + Mode2 = 2 // Use PerformanceConfiguration15 and PerformanceConfiguration16. + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceConfiguration.cs b/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceConfiguration.cs new file mode 100644 index 00000000..e42edebc --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceConfiguration.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Services.Apm +{ + enum PerformanceConfiguration : uint // Clocks are all in MHz. + { // CPU | GPU | RAM | NOTE + PerformanceConfiguration1 = 0x00010000, // 1020 | 384 | 1600 | Only available while docked. + PerformanceConfiguration2 = 0x00010001, // 1020 | 768 | 1600 | Only available while docked. + PerformanceConfiguration3 = 0x00010002, // 1224 | 691.2 | 1600 | Only available for SDEV units. + PerformanceConfiguration4 = 0x00020000, // 1020 | 230.4 | 1600 | Only available for SDEV units. + PerformanceConfiguration5 = 0x00020001, // 1020 | 307.2 | 1600 | + PerformanceConfiguration6 = 0x00020002, // 1224 | 230.4 | 1600 | + PerformanceConfiguration7 = 0x00020003, // 1020 | 307 | 1331.2 | + PerformanceConfiguration8 = 0x00020004, // 1020 | 384 | 1331.2 | + PerformanceConfiguration9 = 0x00020005, // 1020 | 307.2 | 1065.6 | + PerformanceConfiguration10 = 0x00020006, // 1020 | 384 | 1065.6 | + PerformanceConfiguration11 = 0x92220007, // 1020 | 460.8 | 1600 | + PerformanceConfiguration12 = 0x92220008, // 1020 | 460.8 | 1331.2 | + PerformanceConfiguration13 = 0x92220009, // 1785 | 768 | 1600 | 7.0.0+ + PerformanceConfiguration14 = 0x9222000A, // 1785 | 768 | 1331.2 | 7.0.0+ + PerformanceConfiguration15 = 0x9222000B, // 1020 | 768 | 1600 | 7.0.0+ + PerformanceConfiguration16 = 0x9222000C // 1020 | 768 | 1331.2 | 7.0.0+ + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceMode.cs b/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceMode.cs new file mode 100644 index 00000000..a7a0dfad --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/Types/PerformanceMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Apm +{ + enum PerformanceMode + { + Handheld = 0, + Docked = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs new file mode 100644 index 00000000..c1c6d26d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs @@ -0,0 +1,43 @@ +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Utilities; +using System; + +namespace Ryujinx.HLE.HOS.Services.Arp +{ + class ApplicationLaunchProperty + { + public long TitleId; + public int Version; + public byte BaseGameStorageId; + public byte UpdateGameStorageId; + public short Padding; + + public static ApplicationLaunchProperty Default + { + get + { + return new ApplicationLaunchProperty + { + TitleId = 0x00, + Version = 0x00, + BaseGameStorageId = (byte)StorageId.NandSystem, + UpdateGameStorageId = (byte)StorageId.None + }; + } + } + + public static ApplicationLaunchProperty GetByPid(ServiceCtx context) + { + // TODO: Handle ApplicationLaunchProperty as array when pid will be supported and return the right item. + // For now we can hardcode values, and fix it after GetApplicationLaunchProperty is implemented. + + return new ApplicationLaunchProperty + { + TitleId = BitConverter.ToInt64(StringUtils.HexToBytes(context.Device.System.TitleID), 0), + Version = 0x00, + BaseGameStorageId = (byte)StorageId.NandSystem, + UpdateGameStorageId = (byte)StorageId.None + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Arp/IReader.cs b/Ryujinx.HLE/HOS/Services/Arp/IReader.cs new file mode 100644 index 00000000..5d1e2fff --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Arp/IReader.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Service("arp:r")] + class IReader : IpcService + { + public IReader(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs b/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs new file mode 100644 index 00000000..8d13f0fb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Arp +{ + [Service("arp:w")] + class IWriter : IpcService + { + public IWriter(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs deleted file mode 100644 index e25ebe66..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut -{ - [StructLayout(LayoutKind.Sequential)] - struct AudioOutData - { - public long NextBufferPtr; - public long SampleBufferPtr; - public long SampleBufferCapacity; - public long SampleBufferSize; - public long SampleBufferInnerOffset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs deleted file mode 100644 index 751d3f70..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs +++ /dev/null @@ -1,163 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Audio; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut -{ - class IAudioOut : IpcService, IDisposable - { - private IAalOutput _audioOut; - private KEvent _releaseEvent; - private int _track; - - public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track) - { - _audioOut = audioOut; - _releaseEvent = releaseEvent; - _track = track; - } - - [Command(0)] - // GetAudioOutState() -> u32 state - public ResultCode GetAudioOutState(ServiceCtx context) - { - context.ResponseData.Write((int)_audioOut.GetState(_track)); - - return ResultCode.Success; - } - - [Command(1)] - // StartAudioOut() - public ResultCode StartAudioOut(ServiceCtx context) - { - _audioOut.Start(_track); - - return ResultCode.Success; - } - - [Command(2)] - // StopAudioOut() - public ResultCode StopAudioOut(ServiceCtx context) - { - _audioOut.Stop(_track); - - return ResultCode.Success; - } - - [Command(3)] - // AppendAudioOutBuffer(u64 tag, buffer) - public ResultCode AppendAudioOutBuffer(ServiceCtx context) - { - return AppendAudioOutBufferImpl(context, context.Request.SendBuff[0].Position); - } - - [Command(4)] - // RegisterBufferEvent() -> handle - public ResultCode RegisterBufferEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - [Command(5)] - // GetReleasedAudioOutBuffer() -> (u32 count, buffer) - public ResultCode GetReleasedAudioOutBuffer(ServiceCtx context) - { - long position = context.Request.ReceiveBuff[0].Position; - long size = context.Request.ReceiveBuff[0].Size; - - return GetReleasedAudioOutBufferImpl(context, position, size); - } - - [Command(6)] - // ContainsAudioOutBuffer(u64 tag) -> b8 - public ResultCode ContainsAudioOutBuffer(ServiceCtx context) - { - long tag = context.RequestData.ReadInt64(); - - context.ResponseData.Write(_audioOut.ContainsBuffer(_track, tag) ? 1 : 0); - - return 0; - } - - [Command(7)] // 3.0.0+ - // AppendAudioOutBufferAuto(u64 tag, buffer) - public ResultCode AppendAudioOutBufferAuto(ServiceCtx context) - { - (long position, long size) = context.Request.GetBufferType0x21(); - - return AppendAudioOutBufferImpl(context, position); - } - - public ResultCode AppendAudioOutBufferImpl(ServiceCtx context, long position) - { - long tag = context.RequestData.ReadInt64(); - - AudioOutData data = MemoryHelper.Read( - context.Memory, - position); - - byte[] buffer = context.Memory.ReadBytes( - data.SampleBufferPtr, - data.SampleBufferSize); - - _audioOut.AppendBuffer(_track, tag, buffer); - - return ResultCode.Success; - } - - [Command(8)] // 3.0.0+ - // GetReleasedAudioOutBufferAuto() -> (u32 count, buffer) - public ResultCode GetReleasedAudioOutBufferAuto(ServiceCtx context) - { - (long position, long size) = context.Request.GetBufferType0x22(); - - return GetReleasedAudioOutBufferImpl(context, position, size); - } - - public ResultCode GetReleasedAudioOutBufferImpl(ServiceCtx context, long position, long size) - { - uint count = (uint)((ulong)size >> 3); - - long[] releasedBuffers = _audioOut.GetReleasedBuffers(_track, (int)count); - - for (uint index = 0; index < count; index++) - { - long tag = 0; - - if (index < releasedBuffers.Length) - { - tag = releasedBuffers[index]; - } - - context.Memory.WriteInt64(position + index * 8, tag); - } - - context.ResponseData.Write(releasedBuffers.Length); - - return ResultCode.Success; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _audioOut.CloseTrack(_track); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs deleted file mode 100644 index 40788ff3..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - static class AudioConsts - { - public const int HostSampleRate = 48000; - public const int HostChannelsCount = 2; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs deleted file mode 100644 index 69b6d522..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct BehaviorIn - { - public long Unknown0; - public long Unknown8; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs deleted file mode 100644 index 4e0c7c4f..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 1)] - struct BiquadFilter - { - public byte Enable; - public byte Padding; - public short B0; - public short B1; - public short B2; - public short A1; - public short A2; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs deleted file mode 100644 index e8baf819..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs +++ /dev/null @@ -1,404 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Audio; -using Ryujinx.Audio.Adpcm; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.Utilities; -using System; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - class IAudioRenderer : IpcService, IDisposable - { - // This is the amount of samples that are going to be appended - // each time that RequestUpdateAudioRenderer is called. Ideally, - // this value shouldn't be neither too small (to avoid the player - // starving due to running out of samples) or too large (to avoid - // high latency). - private const int MixBufferSamplesCount = 960; - - private KEvent _updateEvent; - - private IMemoryManager _memory; - - private IAalOutput _audioOut; - - private AudioRendererParameter _params; - - private MemoryPoolContext[] _memoryPools; - - private VoiceContext[] _voices; - - private int _track; - - private PlayState _playState; - - public IAudioRenderer( - Horizon system, - IMemoryManager memory, - IAalOutput audioOut, - AudioRendererParameter Params) - { - _updateEvent = new KEvent(system); - - _memory = memory; - _audioOut = audioOut; - _params = Params; - - _track = audioOut.OpenTrack( - AudioConsts.HostSampleRate, - AudioConsts.HostChannelsCount, - AudioCallback); - - _memoryPools = CreateArray(Params.EffectCount + Params.VoiceCount * 4); - - _voices = CreateArray(Params.VoiceCount); - - InitializeAudioOut(); - - _playState = PlayState.Stopped; - } - - [Command(0)] - // GetSampleRate() -> u32 - public ResultCode GetSampleRate(ServiceCtx context) - { - context.ResponseData.Write(_params.SampleRate); - - return ResultCode.Success; - } - - [Command(1)] - // GetSampleCount() -> u32 - public ResultCode GetSampleCount(ServiceCtx context) - { - context.ResponseData.Write(_params.SampleCount); - - return ResultCode.Success; - } - - [Command(2)] - // GetMixBufferCount() -> u32 - public ResultCode GetMixBufferCount(ServiceCtx context) - { - context.ResponseData.Write(_params.MixCount); - - return ResultCode.Success; - } - - [Command(3)] - // GetState() -> u32 - public ResultCode GetState(ServiceCtx context) - { - context.ResponseData.Write((int)_playState); - - Logger.PrintStub(LogClass.ServiceAudio, new { State = Enum.GetName(typeof(PlayState), _playState) }); - - return ResultCode.Success; - } - - private void AudioCallback() - { - _updateEvent.ReadableEvent.Signal(); - } - - private static T[] CreateArray(int size) where T : new() - { - T[] output = new T[size]; - - for (int index = 0; index < size; index++) - { - output[index] = new T(); - } - - return output; - } - - private void InitializeAudioOut() - { - AppendMixedBuffer(0); - AppendMixedBuffer(1); - AppendMixedBuffer(2); - - _audioOut.Start(_track); - } - - [Command(4)] - // RequestUpdateAudioRenderer(buffer) - // -> (buffer, buffer) - public ResultCode RequestUpdateAudioRenderer(ServiceCtx context) - { - long outputPosition = context.Request.ReceiveBuff[0].Position; - long outputSize = context.Request.ReceiveBuff[0].Size; - - MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize); - - long inputPosition = context.Request.SendBuff[0].Position; - - StructReader reader = new StructReader(context.Memory, inputPosition); - StructWriter writer = new StructWriter(context.Memory, outputPosition); - - UpdateDataHeader inputHeader = reader.Read(); - - reader.Read(inputHeader.BehaviorSize); - - MemoryPoolIn[] memoryPoolsIn = reader.Read(inputHeader.MemoryPoolSize); - - for (int index = 0; index < memoryPoolsIn.Length; index++) - { - MemoryPoolIn memoryPool = memoryPoolsIn[index]; - - if (memoryPool.State == MemoryPoolState.RequestAttach) - { - _memoryPools[index].OutStatus.State = MemoryPoolState.Attached; - } - else if (memoryPool.State == MemoryPoolState.RequestDetach) - { - _memoryPools[index].OutStatus.State = MemoryPoolState.Detached; - } - } - - reader.Read(inputHeader.VoiceResourceSize); - - VoiceIn[] voicesIn = reader.Read(inputHeader.VoiceSize); - - for (int index = 0; index < voicesIn.Length; index++) - { - VoiceIn voice = voicesIn[index]; - - VoiceContext voiceCtx = _voices[index]; - - voiceCtx.SetAcquireState(voice.Acquired != 0); - - if (voice.Acquired == 0) - { - continue; - } - - if (voice.FirstUpdate != 0) - { - voiceCtx.AdpcmCtx = GetAdpcmDecoderContext( - voice.AdpcmCoeffsPosition, - voice.AdpcmCoeffsSize); - - voiceCtx.SampleFormat = voice.SampleFormat; - voiceCtx.SampleRate = voice.SampleRate; - voiceCtx.ChannelsCount = voice.ChannelsCount; - - voiceCtx.SetBufferIndex(voice.BaseWaveBufferIndex); - } - - voiceCtx.WaveBuffers[0] = voice.WaveBuffer0; - voiceCtx.WaveBuffers[1] = voice.WaveBuffer1; - voiceCtx.WaveBuffers[2] = voice.WaveBuffer2; - voiceCtx.WaveBuffers[3] = voice.WaveBuffer3; - voiceCtx.Volume = voice.Volume; - voiceCtx.PlayState = voice.PlayState; - } - - UpdateAudio(); - - UpdateDataHeader outputHeader = new UpdateDataHeader(); - - int updateHeaderSize = Marshal.SizeOf(); - - outputHeader.Revision = IAudioRendererManager.RevMagic; - outputHeader.BehaviorSize = 0xb0; - outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10; - outputHeader.VoiceSize = _params.VoiceCount * 0x10; - outputHeader.EffectSize = _params.EffectCount * 0x10; - outputHeader.SinkSize = _params.SinkCount * 0x20; - outputHeader.PerformanceManagerSize = 0x10; - outputHeader.TotalSize = updateHeaderSize + - outputHeader.BehaviorSize + - outputHeader.MemoryPoolSize + - outputHeader.VoiceSize + - outputHeader.EffectSize + - outputHeader.SinkSize + - outputHeader.PerformanceManagerSize; - - writer.Write(outputHeader); - - foreach (MemoryPoolContext memoryPool in _memoryPools) - { - writer.Write(memoryPool.OutStatus); - } - - foreach (VoiceContext voice in _voices) - { - writer.Write(voice.OutStatus); - } - - return ResultCode.Success; - } - - [Command(5)] - // Start() - public ResultCode StartAudioRenderer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAudio); - - _playState = PlayState.Playing; - - return ResultCode.Success; - } - - [Command(6)] - // Stop() - public ResultCode StopAudioRenderer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceAudio); - - _playState = PlayState.Stopped; - - return ResultCode.Success; - } - - [Command(7)] - // QuerySystemEvent() -> handle - public ResultCode QuerySystemEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - private AdpcmDecoderContext GetAdpcmDecoderContext(long position, long size) - { - if (size == 0) - { - return null; - } - - AdpcmDecoderContext context = new AdpcmDecoderContext(); - - context.Coefficients = new short[size >> 1]; - - for (int offset = 0; offset < size; offset += 2) - { - context.Coefficients[offset >> 1] = _memory.ReadInt16(position + offset); - } - - return context; - } - - private void UpdateAudio() - { - long[] released = _audioOut.GetReleasedBuffers(_track, 2); - - for (int index = 0; index < released.Length; index++) - { - AppendMixedBuffer(released[index]); - } - } - - private void AppendMixedBuffer(long tag) - { - int[] mixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; - - foreach (VoiceContext voice in _voices) - { - if (!voice.Playing || voice.CurrentWaveBuffer.Size == 0) - { - continue; - } - - int outOffset = 0; - int pendingSamples = MixBufferSamplesCount; - float volume = voice.Volume; - - while (pendingSamples > 0) - { - int[] samples = voice.GetBufferData(_memory, pendingSamples, out int returnedSamples); - - if (returnedSamples == 0) - { - break; - } - - pendingSamples -= returnedSamples; - - for (int offset = 0; offset < samples.Length; offset++) - { - mixBuffer[outOffset++] += (int)(samples[offset] * voice.Volume); - } - } - } - - _audioOut.AppendBuffer(_track, tag, GetFinalBuffer(mixBuffer)); - } - - private unsafe static short[] GetFinalBuffer(int[] buffer) - { - short[] output = new short[buffer.Length]; - - int offset = 0; - - // Perform Saturation using SSE2 if supported - if (Sse2.IsSupported) - { - fixed (int* inptr = buffer) - fixed (short* outptr = output) - { - for (; offset + 32 <= buffer.Length; offset += 32) - { - // Unroll the loop a little to ensure the CPU pipeline - // is always full. - Vector128 block1A = Sse2.LoadVector128(inptr + offset + 0); - Vector128 block1B = Sse2.LoadVector128(inptr + offset + 4); - - Vector128 block2A = Sse2.LoadVector128(inptr + offset + 8); - Vector128 block2B = Sse2.LoadVector128(inptr + offset + 12); - - Vector128 block3A = Sse2.LoadVector128(inptr + offset + 16); - Vector128 block3B = Sse2.LoadVector128(inptr + offset + 20); - - Vector128 block4A = Sse2.LoadVector128(inptr + offset + 24); - Vector128 block4B = Sse2.LoadVector128(inptr + offset + 28); - - Vector128 output1 = Sse2.PackSignedSaturate(block1A, block1B); - Vector128 output2 = Sse2.PackSignedSaturate(block2A, block2B); - Vector128 output3 = Sse2.PackSignedSaturate(block3A, block3B); - Vector128 output4 = Sse2.PackSignedSaturate(block4A, block4B); - - Sse2.Store(outptr + offset + 0, output1); - Sse2.Store(outptr + offset + 8, output2); - Sse2.Store(outptr + offset + 16, output3); - Sse2.Store(outptr + offset + 24, output4); - } - } - } - - // Process left overs - for (; offset < buffer.Length; offset++) - { - output[offset] = DspUtils.Saturate(buffer[offset]); - } - - return output; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _audioOut.CloseTrack(_track); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs deleted file mode 100644 index c1646065..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - class MemoryPoolContext - { - public MemoryPoolOut OutStatus; - - public MemoryPoolContext() - { - OutStatus.State = MemoryPoolState.Detached; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs deleted file mode 100644 index b4e6594c..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 4)] - struct MemoryPoolIn - { - public long Address; - public long Size; - public MemoryPoolState State; - public int Unknown14; - public long Unknown18; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs deleted file mode 100644 index 6ae583b8..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct MemoryPoolOut - { - public MemoryPoolState State; - public int Unknown14; - public long Unknown18; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs deleted file mode 100644 index 7b672dc9..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - enum MemoryPoolState - { - Invalid = 0, - Unknown = 1, - RequestDetach = 2, - Detached = 3, - RequestAttach = 4, - Attached = 5, - Released = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs deleted file mode 100644 index 922a9dc2..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - enum PlayState : byte - { - Playing = 0, - Stopped = 1, - Paused = 2 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs deleted file mode 100644 index 9714f6d8..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - static class Resampler - { -#region "LookUp Tables" - private static short[] _curveLut0 = new short[] - { - 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22, - 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48, - 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77, - 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109, - 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147, - 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190, - 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241, - 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300, - 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369, - 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449, - 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541, - 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647, - 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766, - 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901, - 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052, - 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221, - 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407, - 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613, - 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838, - 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083, - 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348, - 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635, - 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942, - 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269, - 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618, - 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987, - 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377, - 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785, - 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213, - 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659, - 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121, - 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600 - }; - - private static short[] _curveLut1 = new short[] - { - -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36, - -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80, - -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128, - -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180, - -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240, - -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307, - -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382, - -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468, - -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563, - -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668, - -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783, - -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907, - -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039, - -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176, - -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317, - -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459, - -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599, - -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732, - -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855, - -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962, - -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049, - -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111, - -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141, - -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133, - -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083, - -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984, - -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830, - -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617, - -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338, - -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990, - -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568, - -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68 - }; - - private static short[] _curveLut2 = new short[] - { - 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42, - 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58, - 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76, - 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98, - 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121, - 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146, - 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174, - 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202, - 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230, - 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258, - 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283, - -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306, - -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325, - -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337, - -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341, - -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336, - -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317, - -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284, - -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234, - -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163, - -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71, - -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47, - -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194, - -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371, - -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583, - -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829, - -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115, - -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442, - -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813, - -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227, - -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688, - -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195 - }; -#endregion - - public static int[] Resample2Ch( - int[] buffer, - int srcSampleRate, - int dstSampleRate, - int samplesCount, - ref int fracPart) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (srcSampleRate <= 0) - { - throw new ArgumentOutOfRangeException(nameof(srcSampleRate)); - } - - if (dstSampleRate <= 0) - { - throw new ArgumentOutOfRangeException(nameof(dstSampleRate)); - } - - double ratio = (double)srcSampleRate / dstSampleRate; - - int newSamplesCount = (int)(samplesCount / ratio); - - int step = (int)(ratio * 0x8000); - - int[] output = new int[newSamplesCount * 2]; - - short[] lut; - - if (step > 0xaaaa) - { - lut = _curveLut0; - } - else if (step <= 0x8000) - { - lut = _curveLut1; - } - else - { - lut = _curveLut2; - } - - int inOffs = 0; - - for (int outOffs = 0; outOffs < output.Length; outOffs += 2) - { - int lutIndex = (fracPart >> 8) * 4; - - int sample0 = buffer[(inOffs + 0) * 2 + 0] * lut[lutIndex + 0] + - buffer[(inOffs + 1) * 2 + 0] * lut[lutIndex + 1] + - buffer[(inOffs + 2) * 2 + 0] * lut[lutIndex + 2] + - buffer[(inOffs + 3) * 2 + 0] * lut[lutIndex + 3]; - - int sample1 = buffer[(inOffs + 0) * 2 + 1] * lut[lutIndex + 0] + - buffer[(inOffs + 1) * 2 + 1] * lut[lutIndex + 1] + - buffer[(inOffs + 2) * 2 + 1] * lut[lutIndex + 2] + - buffer[(inOffs + 3) * 2 + 1] * lut[lutIndex + 3]; - - int newOffset = fracPart + step; - - inOffs += newOffset >> 15; - - fracPart = newOffset & 0x7fff; - - output[outOffs + 0] = sample0 >> 15; - output[outOffs + 1] = sample1 >> 15; - } - - return output; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs deleted file mode 100644 index 04fe422c..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - struct UpdateDataHeader - { - public int Revision; - public int BehaviorSize; - public int MemoryPoolSize; - public int VoiceSize; - public int VoiceResourceSize; - public int EffectSize; - public int MixeSize; - public int SinkSize; - public int PerformanceManagerSize; - public int Unknown24; - public int Unknown28; - public int Unknown2C; - public int Unknown30; - public int Unknown34; - public int Unknown38; - public int TotalSize; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs deleted file mode 100644 index 124d31be..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)] - struct VoiceChannelResourceIn - { - // ??? - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs deleted file mode 100644 index aaff20a5..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs +++ /dev/null @@ -1,199 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Audio.Adpcm; -using System; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - class VoiceContext - { - private bool _acquired; - private bool _bufferReload; - - private int _resamplerFracPart; - - private int _bufferIndex; - private int _offset; - - public int SampleRate { get; set; } - public int ChannelsCount { get; set; } - - public float Volume { get; set; } - - public PlayState PlayState { get; set; } - - public SampleFormat SampleFormat { get; set; } - - public AdpcmDecoderContext AdpcmCtx { get; set; } - - public WaveBuffer[] WaveBuffers { get; } - - public WaveBuffer CurrentWaveBuffer => WaveBuffers[_bufferIndex]; - - private VoiceOut _outStatus; - - public VoiceOut OutStatus => _outStatus; - - private int[] _samples; - - public bool Playing => _acquired && PlayState == PlayState.Playing; - - public VoiceContext() - { - WaveBuffers = new WaveBuffer[4]; - } - - public void SetAcquireState(bool newState) - { - if (_acquired && !newState) - { - // Release. - Reset(); - } - - _acquired = newState; - } - - private void Reset() - { - _bufferReload = true; - - _bufferIndex = 0; - _offset = 0; - - _outStatus.PlayedSamplesCount = 0; - _outStatus.PlayedWaveBuffersCount = 0; - _outStatus.VoiceDropsCount = 0; - } - - public int[] GetBufferData(IMemoryManager memory, int maxSamples, out int samplesCount) - { - if (!Playing) - { - samplesCount = 0; - - return null; - } - - if (_bufferReload) - { - _bufferReload = false; - - UpdateBuffer(memory); - } - - WaveBuffer wb = WaveBuffers[_bufferIndex]; - - int maxSize = _samples.Length - _offset; - - int size = maxSamples * AudioConsts.HostChannelsCount; - - if (size > maxSize) - { - size = maxSize; - } - - int[] output = new int[size]; - - Array.Copy(_samples, _offset, output, 0, size); - - samplesCount = size / AudioConsts.HostChannelsCount; - - _outStatus.PlayedSamplesCount += samplesCount; - - _offset += size; - - if (_offset == _samples.Length) - { - _offset = 0; - - if (wb.Looping == 0) - { - SetBufferIndex((_bufferIndex + 1) & 3); - } - - _outStatus.PlayedWaveBuffersCount++; - - if (wb.LastBuffer != 0) - { - PlayState = PlayState.Paused; - } - } - - return output; - } - - private void UpdateBuffer(IMemoryManager memory) - { - // TODO: Implement conversion for formats other - // than interleaved stereo (2 channels). - // As of now, it assumes that HostChannelsCount == 2. - WaveBuffer wb = WaveBuffers[_bufferIndex]; - - if (wb.Position == 0) - { - _samples = new int[0]; - - return; - } - - if (SampleFormat == SampleFormat.PcmInt16) - { - int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount)); - - _samples = new int[samplesCount * AudioConsts.HostChannelsCount]; - - if (ChannelsCount == 1) - { - for (int index = 0; index < samplesCount; index++) - { - short sample = memory.ReadInt16(wb.Position + index * 2); - - _samples[index * 2 + 0] = sample; - _samples[index * 2 + 1] = sample; - } - } - else - { - for (int index = 0; index < samplesCount * 2; index++) - { - _samples[index] = memory.ReadInt16(wb.Position + index * 2); - } - } - } - else if (SampleFormat == SampleFormat.Adpcm) - { - byte[] buffer = memory.ReadBytes(wb.Position, wb.Size); - - _samples = AdpcmDecoder.Decode(buffer, AdpcmCtx); - } - else - { - throw new InvalidOperationException(); - } - - if (SampleRate != AudioConsts.HostSampleRate) - { - // TODO: We should keep the frames being discarded (see the 4 below) - // on a buffer and include it on the next samples buffer, to allow - // the resampler to do seamless interpolation between wave buffers. - int samplesCount = _samples.Length / AudioConsts.HostChannelsCount; - - samplesCount = Math.Max(samplesCount - 4, 0); - - _samples = Resampler.Resample2Ch( - _samples, - SampleRate, - AudioConsts.HostSampleRate, - samplesCount, - ref _resamplerFracPart); - } - } - - public void SetBufferIndex(int index) - { - _bufferIndex = index & 3; - - _bufferReload = true; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs deleted file mode 100644 index 143cf4d8..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)] - struct VoiceIn - { - public int VoiceSlot; - public int NodeId; - - public byte FirstUpdate; - public byte Acquired; - - public PlayState PlayState; - - public SampleFormat SampleFormat; - - public int SampleRate; - - public int Priority; - - public int Unknown14; - - public int ChannelsCount; - - public float Pitch; - public float Volume; - - public BiquadFilter BiquadFilter0; - public BiquadFilter BiquadFilter1; - - public int AppendedWaveBuffersCount; - - public int BaseWaveBufferIndex; - - public int Unknown44; - - public long AdpcmCoeffsPosition; - public long AdpcmCoeffsSize; - - public int VoiceDestination; - public int Padding; - - public WaveBuffer WaveBuffer0; - public WaveBuffer WaveBuffer1; - public WaveBuffer WaveBuffer2; - public WaveBuffer WaveBuffer3; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs deleted file mode 100644 index 5332631d..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct VoiceOut - { - public long PlayedSamplesCount; - public int PlayedWaveBuffersCount; - public int VoiceDropsCount; //? - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs deleted file mode 100644 index 89137ec0..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)] - struct WaveBuffer - { - public long Position; - public long Size; - public int FirstSampleOffset; - public int LastSampleOffset; - public byte Looping; - public byte LastBuffer; - public short Unknown1A; - public int Unknown1C; - public long AdpcmLoopContextPosition; - public long AdpcmLoopContextSize; - public long Unknown30; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs deleted file mode 100644 index 812ef8cf..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Aud -{ - [StructLayout(LayoutKind.Sequential)] - struct AudioRendererParameter - { - public int SampleRate; - public int SampleCount; - public int Unknown8; - public int MixCount; - public int VoiceCount; - public int SinkCount; - public int EffectCount; - public int PerformanceManagerCount; - public int VoiceDropEnable; - public int SplitterCount; - public int SplitterDestinationDataCount; - public int Unknown2C; - public int Revision; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs deleted file mode 100644 index 48a2fb74..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs +++ /dev/null @@ -1,236 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.SystemState; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Aud -{ - class IAudioDevice : IpcService - { - private KEvent _systemEvent; - - public IAudioDevice(Horizon system) - { - _systemEvent = new KEvent(system); - - // TODO: We shouldn't be signaling this here. - _systemEvent.ReadableEvent.Signal(); - } - - [Command(0)] - // ListAudioDeviceName() -> (u32, buffer) - public ResultCode ListAudioDeviceName(ServiceCtx context) - { - string[] deviceNames = SystemStateMgr.AudioOutputs; - - context.ResponseData.Write(deviceNames.Length); - - long position = context.Request.ReceiveBuff[0].Position; - long size = context.Request.ReceiveBuff[0].Size; - - long basePosition = position; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.ASCII.GetBytes(name + "\0"); - - if ((position - basePosition) + buffer.Length > size) - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.WriteBytes(position, buffer); - - position += buffer.Length; - } - - return ResultCode.Success; - } - - [Command(1)] - // SetAudioDeviceOutputVolume(u32, buffer) - public ResultCode SetAudioDeviceOutputVolume(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - long position = context.Request.SendBuff[0].Position; - long size = context.Request.SendBuff[0].Size; - - byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size); - - string deviceName = Encoding.ASCII.GetString(deviceNameBuffer); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(3)] - // GetActiveAudioDeviceName() -> buffer - public ResultCode GetActiveAudioDeviceName(ServiceCtx context) - { - string name = context.Device.System.State.ActiveAudioOutput; - - long position = context.Request.ReceiveBuff[0].Position; - long size = context.Request.ReceiveBuff[0].Size; - - byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0"); - - if ((ulong)deviceNameBuffer.Length <= (ulong)size) - { - context.Memory.WriteBytes(position, deviceNameBuffer); - } - else - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - return ResultCode.Success; - } - - [Command(4)] - // QueryAudioDeviceSystemEvent() -> handle - public ResultCode QueryAudioDeviceSystemEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(5)] - // GetActiveChannelCount() -> u32 - public ResultCode GetActiveChannelCount(ServiceCtx context) - { - context.ResponseData.Write(2); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(6)] - // ListAudioDeviceNameAuto() -> (u32, buffer) - public ResultCode ListAudioDeviceNameAuto(ServiceCtx context) - { - string[] deviceNames = SystemStateMgr.AudioOutputs; - - context.ResponseData.Write(deviceNames.Length); - - (long position, long size) = context.Request.GetBufferType0x22(); - - long basePosition = position; - - foreach (string name in deviceNames) - { - byte[] buffer = Encoding.UTF8.GetBytes(name + '\0'); - - if ((position - basePosition) + buffer.Length > size) - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - - break; - } - - context.Memory.WriteBytes(position, buffer); - - position += buffer.Length; - } - - return ResultCode.Success; - } - - [Command(7)] - // SetAudioDeviceOutputVolumeAuto(u32, buffer) - public ResultCode SetAudioDeviceOutputVolumeAuto(ServiceCtx context) - { - float volume = context.RequestData.ReadSingle(); - - (long position, long size) = context.Request.GetBufferType0x21(); - - byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size); - - string deviceName = Encoding.UTF8.GetString(deviceNameBuffer); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(8)] - // GetAudioDeviceOutputVolumeAuto(buffer) -> u32 - public ResultCode GetAudioDeviceOutputVolumeAuto(ServiceCtx context) - { - context.ResponseData.Write(1f); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(10)] - // GetActiveAudioDeviceNameAuto() -> buffer - public ResultCode GetActiveAudioDeviceNameAuto(ServiceCtx context) - { - string name = context.Device.System.State.ActiveAudioOutput; - - (long position, long size) = context.Request.GetBufferType0x22(); - - byte[] deviceNameBuffer = Encoding.UTF8.GetBytes(name + '\0'); - - if ((ulong)deviceNameBuffer.Length <= (ulong)size) - { - context.Memory.WriteBytes(position, deviceNameBuffer); - } - else - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - return ResultCode.Success; - } - - [Command(11)] - // QueryAudioDeviceInputEvent() -> handle - public ResultCode QueryAudioDeviceInputEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - - [Command(12)] - // QueryAudioDeviceOutputEvent() -> handle - public ResultCode QueryAudioDeviceOutputEvent(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - Logger.PrintStub(LogClass.ServiceAudio); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs deleted file mode 100644 index bea0f3f2..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs +++ /dev/null @@ -1,162 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Audio; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Aud.AudioOut; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Aud -{ - [Service("audout:u")] - class IAudioOutManager : IpcService - { - private const string DefaultAudioOutput = "DeviceOut"; - private const int DefaultSampleRate = 48000; - private const int DefaultChannelsCount = 2; - - public IAudioOutManager(ServiceCtx context) { } - - [Command(0)] - // ListAudioOuts() -> (u32 count, buffer) - public ResultCode ListAudioOuts(ServiceCtx context) - { - return ListAudioOutsImpl( - context, - context.Request.ReceiveBuff[0].Position, - context.Request.ReceiveBuff[0].Size); - } - - [Command(1)] - // OpenAudioOut(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle, buffer name_in) - // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name_out) - public ResultCode OpenAudioOut(ServiceCtx context) - { - return OpenAudioOutImpl( - context, - context.Request.SendBuff[0].Position, - context.Request.SendBuff[0].Size, - context.Request.ReceiveBuff[0].Position, - context.Request.ReceiveBuff[0].Size); - } - - [Command(2)] // 3.0.0+ - // ListAudioOutsAuto() -> (u32 count, buffer) - public ResultCode ListAudioOutsAuto(ServiceCtx context) - { - (long recvPosition, long recvSize) = context.Request.GetBufferType0x22(); - - return ListAudioOutsImpl(context, recvPosition, recvSize); - } - - [Command(3)] // 3.0.0+ - // OpenAudioOutAuto(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle, buffer) - // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name_out) - public ResultCode OpenAudioOutAuto(ServiceCtx context) - { - (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); - (long recvPosition, long recvSize) = context.Request.GetBufferType0x22(); - - return OpenAudioOutImpl( - context, - sendPosition, - sendSize, - recvPosition, - recvSize); - } - - private ResultCode ListAudioOutsImpl(ServiceCtx context, long position, long size) - { - int nameCount = 0; - - byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0"); - - if ((ulong)deviceNameBuffer.Length <= (ulong)size) - { - context.Memory.WriteBytes(position, deviceNameBuffer); - - nameCount++; - } - else - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); - } - - context.ResponseData.Write(nameCount); - - return ResultCode.Success; - } - - private ResultCode OpenAudioOutImpl(ServiceCtx context, long sendPosition, long sendSize, long receivePosition, long receiveSize) - { - string deviceName = MemoryHelper.ReadAsciiString( - context.Memory, - sendPosition, - sendSize); - - if (deviceName == string.Empty) - { - deviceName = DefaultAudioOutput; - } - - if (deviceName != DefaultAudioOutput) - { - Logger.PrintWarning(LogClass.Audio, "Invalid device name!"); - - return ResultCode.DeviceNotFound; - } - - byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(deviceName + "\0"); - - if ((ulong)deviceNameBuffer.Length <= (ulong)receiveSize) - { - context.Memory.WriteBytes(receivePosition, deviceNameBuffer); - } - else - { - Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {receiveSize} too small!"); - } - - int sampleRate = context.RequestData.ReadInt32(); - int channels = context.RequestData.ReadInt32(); - - if (sampleRate == 0) - { - sampleRate = DefaultSampleRate; - } - - if (sampleRate != DefaultSampleRate) - { - Logger.PrintWarning(LogClass.Audio, "Invalid sample rate!"); - - return ResultCode.UnsupportedSampleRate; - } - - channels = (ushort)channels; - - if (channels == 0) - { - channels = DefaultChannelsCount; - } - - KEvent releaseEvent = new KEvent(context.Device.System); - - ReleaseCallback callback = () => - { - releaseEvent.ReadableEvent.Signal(); - }; - - IAalOutput audioOut = context.Device.AudioOut; - - int track = audioOut.OpenTrack(sampleRate, channels, callback); - - MakeObject(context, new IAudioOut(audioOut, releaseEvent, track)); - - context.ResponseData.Write(sampleRate); - context.ResponseData.Write(channels); - context.ResponseData.Write((int)SampleFormat.PcmInt16); - context.ResponseData.Write((int)PlaybackState.Stopped); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs deleted file mode 100644 index 29bf8320..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs +++ /dev/null @@ -1,192 +0,0 @@ -using Ryujinx.Audio; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer; -using Ryujinx.HLE.Utilities; - -namespace Ryujinx.HLE.HOS.Services.Aud -{ - [Service("audren:u")] - class IAudioRendererManager : IpcService - { - private const int Rev0Magic = ('R' << 0) | - ('E' << 8) | - ('V' << 16) | - ('0' << 24); - - private const int Rev = 5; - - public const int RevMagic = Rev0Magic + (Rev << 24); - - public IAudioRendererManager(ServiceCtx context) { } - - [Command(0)] - // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle, handle) - // -> object - public ResultCode OpenAudioRenderer(ServiceCtx context) - { - IAalOutput audioOut = context.Device.AudioOut; - - AudioRendererParameter Params = GetAudioRendererParameter(context); - - MakeObject(context, new IAudioRenderer( - context.Device.System, - context.Memory, - audioOut, - Params)); - - return ResultCode.Success; - } - - [Command(1)] - // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64 - public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context) - { - AudioRendererParameter Params = GetAudioRendererParameter(context); - - int revision = (Params.Revision - Rev0Magic) >> 24; - - if (revision <= Rev) - { - bool isSplitterSupported = revision >= 3; - bool isVariadicCommandBufferSizeSupported = revision >= 5; - - long size; - - size = IntUtils.AlignUp(Params.Unknown8 * 4, 64); - size += Params.MixCount * 0x400; - size += (Params.MixCount + 1) * 0x940; - size += Params.VoiceCount * 0x3F0; - size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16); - size += IntUtils.AlignUp(Params.VoiceCount * 8, 16); - size += IntUtils.AlignUp( - ((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) * - (Params.Unknown8 + 6), 64); - size += (Params.SinkCount + Params.MixCount) * 0x2C0; - size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50; - - if (isSplitterSupported) - { - size += IntUtils.AlignUp(( - NodeStatesGetWorkBufferSize(Params.MixCount + 1) + - EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16); - - size += Params.SplitterDestinationDataCount * 0xE0; - size += Params.SplitterCount * 0x20; - size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16); - } - - size = Params.EffectCount * 0x4C0 + - Params.SinkCount * 0x170 + - Params.VoiceCount * 0x100 + - IntUtils.AlignUp(size, 64) + 0x40; - - if (Params.PerformanceManagerCount >= 1) - { - size += (((Params.EffectCount + - Params.SinkCount + - Params.VoiceCount + - Params.MixCount + 1) * 16 + 0x658) * - (Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL; - } - - if (isVariadicCommandBufferSizeSupported) - { - size += Params.EffectCount * 0x840 + - Params.MixCount * 0x5A38 + - Params.SinkCount * 0x148 + - Params.SplitterDestinationDataCount * 0x540 + - Params.VoiceCount * (Params.SplitterCount * 0x68 + 0x2E0) + - ((Params.VoiceCount + Params.MixCount + Params.EffectCount + Params.SinkCount + 0x65) << 6) + 0x3F8 + 0x7E; - } - else - { - size += 0x1807E; - } - - size = size & ~0xFFFL; - - context.ResponseData.Write(size); - - Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}."); - - return ResultCode.Success; - } - else - { - context.ResponseData.Write(0L); - - Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!"); - - return ResultCode.UnsupportedRevision; - } - } - - private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context) - { - AudioRendererParameter Params = new AudioRendererParameter(); - - Params.SampleRate = context.RequestData.ReadInt32(); - Params.SampleCount = context.RequestData.ReadInt32(); - Params.Unknown8 = context.RequestData.ReadInt32(); - Params.MixCount = context.RequestData.ReadInt32(); - Params.VoiceCount = context.RequestData.ReadInt32(); - Params.SinkCount = context.RequestData.ReadInt32(); - Params.EffectCount = context.RequestData.ReadInt32(); - Params.PerformanceManagerCount = context.RequestData.ReadInt32(); - Params.VoiceDropEnable = context.RequestData.ReadInt32(); - Params.SplitterCount = context.RequestData.ReadInt32(); - Params.SplitterDestinationDataCount = context.RequestData.ReadInt32(); - Params.Unknown2C = context.RequestData.ReadInt32(); - Params.Revision = context.RequestData.ReadInt32(); - - return Params; - } - - private static int NodeStatesGetWorkBufferSize(int value) - { - int result = IntUtils.AlignUp(value, 64); - - if (result < 0) - { - result |= 7; - } - - return 4 * (value * value) + 0x12 * value + 2 * (result / 8); - } - - private static int EdgeMatrixGetWorkBufferSize(int value) - { - int result = IntUtils.AlignUp(value * value, 64); - - if (result < 0) - { - result |= 7; - } - - return result / 8; - } - - [Command(2)] - // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object - public ResultCode GetAudioDeviceService(ServiceCtx context) - { - long appletResourceUserId = context.RequestData.ReadInt64(); - - MakeObject(context, new IAudioDevice(context.Device.System)); - - return ResultCode.Success; - } - - [Command(4)] // 4.0.0+ - // GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object - public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context) - { - long appletResourceUserId = context.RequestData.ReadInt64(); - int revisionInfo = context.RequestData.ReadInt32(); - - Logger.PrintStub(LogClass.ServiceAudio, new { appletResourceUserId, revisionInfo }); - - return GetAudioDeviceService(context); - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs b/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs deleted file mode 100644 index 148a69a8..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Concentus.Structs; - -namespace Ryujinx.HLE.HOS.Services.Aud -{ - class IHardwareOpusDecoder : IpcService - { - private const int FixedSampleRate = 48000; - - private int _sampleRate; - private int _channelsCount; - - private OpusDecoder _decoder; - - public IHardwareOpusDecoder(int sampleRate, int channelsCount) - { - _sampleRate = sampleRate; - _channelsCount = channelsCount; - - _decoder = new OpusDecoder(FixedSampleRate, channelsCount); - } - - [Command(0)] - // DecodeInterleaved(buffer) -> (u32, u32, buffer) - public ResultCode DecodeInterleaved(ServiceCtx context) - { - long inPosition = context.Request.SendBuff[0].Position; - long inSize = context.Request.SendBuff[0].Size; - - if (inSize < 8) - { - return ResultCode.OpusInvalidInput; - } - - long outPosition = context.Request.ReceiveBuff[0].Position; - long outSize = context.Request.ReceiveBuff[0].Size; - - byte[] opusData = context.Memory.ReadBytes(inPosition, inSize); - - int processed = ((opusData[0] << 24) | - (opusData[1] << 16) | - (opusData[2] << 8) | - (opusData[3] << 0)) + 8; - - if ((uint)processed > (ulong)inSize) - { - return ResultCode.OpusInvalidInput; - } - - short[] pcm = new short[outSize / 2]; - - int frameSize = pcm.Length / (_channelsCount * 2); - - int samples = _decoder.Decode(opusData, 0, opusData.Length, pcm, 0, frameSize); - - foreach (short sample in pcm) - { - context.Memory.WriteInt16(outPosition, sample); - - outPosition += 2; - } - - context.ResponseData.Write(processed); - context.ResponseData.Write(samples); - - return ResultCode.Success; - } - - [Command(4)] - // DecodeInterleavedWithPerf(buffer) -> (u32, u32, u64, buffer) - public ResultCode DecodeInterleavedWithPerf(ServiceCtx context) - { - ResultCode result = DecodeInterleaved(context); - - // TODO: Figure out what this value is. - // According to switchbrew, it is now used. - context.ResponseData.Write(0L); - - return result; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs deleted file mode 100644 index 042be626..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud -{ - [Service("hwopus")] - class IHardwareOpusDecoderManager : IpcService - { - public IHardwareOpusDecoderManager(ServiceCtx context) { } - - [Command(0)] - // Initialize(bytes<8, 4>, u32, handle) -> object - public ResultCode Initialize(ServiceCtx context) - { - int sampleRate = context.RequestData.ReadInt32(); - int channelsCount = context.RequestData.ReadInt32(); - - MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount)); - - return ResultCode.Success; - } - - [Command(1)] - // GetWorkBufferSize(bytes<8, 4>) -> u32 - public ResultCode GetWorkBufferSize(ServiceCtx context) - { - // Note: The sample rate is ignored because it is fixed to 48KHz. - int sampleRate = context.RequestData.ReadInt32(); - int channelsCount = context.RequestData.ReadInt32(); - - context.ResponseData.Write(GetOpusDecoderSize(channelsCount)); - - return ResultCode.Success; - } - - private static int GetOpusDecoderSize(int channelsCount) - { - const int silkDecoderSize = 0x2198; - - if (channelsCount < 1 || channelsCount > 2) - { - return 0; - } - - int celtDecoderSize = GetCeltDecoderSize(channelsCount); - - int opusDecoderSize = (channelsCount * 0x800 + 0x4807) & -0x800 | 0x50; - - return opusDecoderSize + silkDecoderSize + celtDecoderSize; - } - - private static int GetCeltDecoderSize(int channelsCount) - { - const int decodeBufferSize = 0x2030; - const int celtDecoderSize = 0x58; - const int celtSigSize = 0x4; - const int overlap = 120; - const int eBandsCount = 21; - - return (decodeBufferSize + overlap * 4) * channelsCount + - eBandsCount * 16 + - celtDecoderSize + - celtSigSize; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Aud/ResultCode.cs deleted file mode 100644 index d49964d6..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/ResultCode.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud -{ - enum ResultCode - { - ModuleId = 153, - ErrorCodeShift = 9, - - Success = 0, - - DeviceNotFound = (1 << ErrorCodeShift) | ModuleId, - UnsupportedRevision = (2 << ErrorCodeShift) | ModuleId, - UnsupportedSampleRate = (3 << ErrorCodeShift) | ModuleId, - OpusInvalidInput = (6 << ErrorCodeShift) | ModuleId - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs b/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs deleted file mode 100644 index 8da80381..00000000 --- a/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Aud -{ - enum SampleFormat : byte - { - Invalid = 0, - PcmInt8 = 1, - PcmInt16 = 2, - PcmInt24 = 3, - PcmInt32 = 4, - PcmFloat = 5, - Adpcm = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs new file mode 100644 index 00000000..5b6983d6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs @@ -0,0 +1,163 @@ +using ARMeilleure.Memory; +using Ryujinx.Audio; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager +{ + class IAudioOut : IpcService, IDisposable + { + private IAalOutput _audioOut; + private KEvent _releaseEvent; + private int _track; + + public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track) + { + _audioOut = audioOut; + _releaseEvent = releaseEvent; + _track = track; + } + + [Command(0)] + // GetAudioOutState() -> u32 state + public ResultCode GetAudioOutState(ServiceCtx context) + { + context.ResponseData.Write((int)_audioOut.GetState(_track)); + + return ResultCode.Success; + } + + [Command(1)] + // StartAudioOut() + public ResultCode StartAudioOut(ServiceCtx context) + { + _audioOut.Start(_track); + + return ResultCode.Success; + } + + [Command(2)] + // StopAudioOut() + public ResultCode StopAudioOut(ServiceCtx context) + { + _audioOut.Stop(_track); + + return ResultCode.Success; + } + + [Command(3)] + // AppendAudioOutBuffer(u64 tag, buffer) + public ResultCode AppendAudioOutBuffer(ServiceCtx context) + { + return AppendAudioOutBufferImpl(context, context.Request.SendBuff[0].Position); + } + + [Command(4)] + // RegisterBufferEvent() -> handle + public ResultCode RegisterBufferEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + [Command(5)] + // GetReleasedAudioOutBuffer() -> (u32 count, buffer) + public ResultCode GetReleasedAudioOutBuffer(ServiceCtx context) + { + long position = context.Request.ReceiveBuff[0].Position; + long size = context.Request.ReceiveBuff[0].Size; + + return GetReleasedAudioOutBufferImpl(context, position, size); + } + + [Command(6)] + // ContainsAudioOutBuffer(u64 tag) -> b8 + public ResultCode ContainsAudioOutBuffer(ServiceCtx context) + { + long tag = context.RequestData.ReadInt64(); + + context.ResponseData.Write(_audioOut.ContainsBuffer(_track, tag) ? 1 : 0); + + return 0; + } + + [Command(7)] // 3.0.0+ + // AppendAudioOutBufferAuto(u64 tag, buffer) + public ResultCode AppendAudioOutBufferAuto(ServiceCtx context) + { + (long position, long size) = context.Request.GetBufferType0x21(); + + return AppendAudioOutBufferImpl(context, position); + } + + public ResultCode AppendAudioOutBufferImpl(ServiceCtx context, long position) + { + long tag = context.RequestData.ReadInt64(); + + AudioOutData data = MemoryHelper.Read( + context.Memory, + position); + + byte[] buffer = context.Memory.ReadBytes( + data.SampleBufferPtr, + data.SampleBufferSize); + + _audioOut.AppendBuffer(_track, tag, buffer); + + return ResultCode.Success; + } + + [Command(8)] // 3.0.0+ + // GetReleasedAudioOutBufferAuto() -> (u32 count, buffer) + public ResultCode GetReleasedAudioOutBufferAuto(ServiceCtx context) + { + (long position, long size) = context.Request.GetBufferType0x22(); + + return GetReleasedAudioOutBufferImpl(context, position, size); + } + + public ResultCode GetReleasedAudioOutBufferImpl(ServiceCtx context, long position, long size) + { + uint count = (uint)((ulong)size >> 3); + + long[] releasedBuffers = _audioOut.GetReleasedBuffers(_track, (int)count); + + for (uint index = 0; index < count; index++) + { + long tag = 0; + + if (index < releasedBuffers.Length) + { + tag = releasedBuffers[index]; + } + + context.Memory.WriteInt64(position + index * 8, tag); + } + + context.ResponseData.Write(releasedBuffers.Length); + + return ResultCode.Success; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _audioOut.CloseTrack(_track); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/Types/AudioOutData.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/Types/AudioOutData.cs new file mode 100644 index 00000000..2598d0f8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/Types/AudioOutData.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager +{ + [StructLayout(LayoutKind.Sequential)] + struct AudioOutData + { + public long NextBufferPtr; + public long SampleBufferPtr; + public long SampleBufferCapacity; + public long SampleBufferSize; + public long SampleBufferInnerOffset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs new file mode 100644 index 00000000..ab4aee76 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs @@ -0,0 +1,236 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.SystemState; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class IAudioDevice : IpcService + { + private KEvent _systemEvent; + + public IAudioDevice(Horizon system) + { + _systemEvent = new KEvent(system); + + // TODO: We shouldn't be signaling this here. + _systemEvent.ReadableEvent.Signal(); + } + + [Command(0)] + // ListAudioDeviceName() -> (u32, buffer) + public ResultCode ListAudioDeviceName(ServiceCtx context) + { + string[] deviceNames = SystemStateMgr.AudioOutputs; + + context.ResponseData.Write(deviceNames.Length); + + long position = context.Request.ReceiveBuff[0].Position; + long size = context.Request.ReceiveBuff[0].Size; + + long basePosition = position; + + foreach (string name in deviceNames) + { + byte[] buffer = Encoding.ASCII.GetBytes(name + "\0"); + + if ((position - basePosition) + buffer.Length > size) + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); + + break; + } + + context.Memory.WriteBytes(position, buffer); + + position += buffer.Length; + } + + return ResultCode.Success; + } + + [Command(1)] + // SetAudioDeviceOutputVolume(u32, buffer) + public ResultCode SetAudioDeviceOutputVolume(ServiceCtx context) + { + float volume = context.RequestData.ReadSingle(); + + long position = context.Request.SendBuff[0].Position; + long size = context.Request.SendBuff[0].Size; + + byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size); + + string deviceName = Encoding.ASCII.GetString(deviceNameBuffer); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(3)] + // GetActiveAudioDeviceName() -> buffer + public ResultCode GetActiveAudioDeviceName(ServiceCtx context) + { + string name = context.Device.System.State.ActiveAudioOutput; + + long position = context.Request.ReceiveBuff[0].Position; + long size = context.Request.ReceiveBuff[0].Size; + + byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0"); + + if ((ulong)deviceNameBuffer.Length <= (ulong)size) + { + context.Memory.WriteBytes(position, deviceNameBuffer); + } + else + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); + } + + return ResultCode.Success; + } + + [Command(4)] + // QueryAudioDeviceSystemEvent() -> handle + public ResultCode QueryAudioDeviceSystemEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(5)] + // GetActiveChannelCount() -> u32 + public ResultCode GetActiveChannelCount(ServiceCtx context) + { + context.ResponseData.Write(2); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(6)] + // ListAudioDeviceNameAuto() -> (u32, buffer) + public ResultCode ListAudioDeviceNameAuto(ServiceCtx context) + { + string[] deviceNames = SystemStateMgr.AudioOutputs; + + context.ResponseData.Write(deviceNames.Length); + + (long position, long size) = context.Request.GetBufferType0x22(); + + long basePosition = position; + + foreach (string name in deviceNames) + { + byte[] buffer = Encoding.UTF8.GetBytes(name + '\0'); + + if ((position - basePosition) + buffer.Length > size) + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); + + break; + } + + context.Memory.WriteBytes(position, buffer); + + position += buffer.Length; + } + + return ResultCode.Success; + } + + [Command(7)] + // SetAudioDeviceOutputVolumeAuto(u32, buffer) + public ResultCode SetAudioDeviceOutputVolumeAuto(ServiceCtx context) + { + float volume = context.RequestData.ReadSingle(); + + (long position, long size) = context.Request.GetBufferType0x21(); + + byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size); + + string deviceName = Encoding.UTF8.GetString(deviceNameBuffer); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(8)] + // GetAudioDeviceOutputVolumeAuto(buffer) -> u32 + public ResultCode GetAudioDeviceOutputVolumeAuto(ServiceCtx context) + { + context.ResponseData.Write(1f); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(10)] + // GetActiveAudioDeviceNameAuto() -> buffer + public ResultCode GetActiveAudioDeviceNameAuto(ServiceCtx context) + { + string name = context.Device.System.State.ActiveAudioOutput; + + (long position, long size) = context.Request.GetBufferType0x22(); + + byte[] deviceNameBuffer = Encoding.UTF8.GetBytes(name + '\0'); + + if ((ulong)deviceNameBuffer.Length <= (ulong)size) + { + context.Memory.WriteBytes(position, deviceNameBuffer); + } + else + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); + } + + return ResultCode.Success; + } + + [Command(11)] + // QueryAudioDeviceInputEvent() -> handle + public ResultCode QueryAudioDeviceInputEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + + [Command(12)] + // QueryAudioDeviceOutputEvent() -> handle + public ResultCode QueryAudioDeviceOutputEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + Logger.PrintStub(LogClass.ServiceAudio); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs new file mode 100644 index 00000000..975992aa --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs @@ -0,0 +1,405 @@ +using ARMeilleure.Memory; +using Ryujinx.Audio; +using Ryujinx.Audio.Adpcm; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.Utilities; +using System; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class IAudioRenderer : IpcService, IDisposable + { + // This is the amount of samples that are going to be appended + // each time that RequestUpdateAudioRenderer is called. Ideally, + // this value shouldn't be neither too small (to avoid the player + // starving due to running out of samples) or too large (to avoid + // high latency). + private const int MixBufferSamplesCount = 960; + + private KEvent _updateEvent; + + private IMemoryManager _memory; + + private IAalOutput _audioOut; + + private AudioRendererParameter _params; + + private MemoryPoolContext[] _memoryPools; + + private VoiceContext[] _voices; + + private int _track; + + private PlayState _playState; + + public IAudioRenderer( + Horizon system, + IMemoryManager memory, + IAalOutput audioOut, + AudioRendererParameter Params) + { + _updateEvent = new KEvent(system); + + _memory = memory; + _audioOut = audioOut; + _params = Params; + + _track = audioOut.OpenTrack( + AudioConsts.HostSampleRate, + AudioConsts.HostChannelsCount, + AudioCallback); + + _memoryPools = CreateArray(Params.EffectCount + Params.VoiceCount * 4); + + _voices = CreateArray(Params.VoiceCount); + + InitializeAudioOut(); + + _playState = PlayState.Stopped; + } + + [Command(0)] + // GetSampleRate() -> u32 + public ResultCode GetSampleRate(ServiceCtx context) + { + context.ResponseData.Write(_params.SampleRate); + + return ResultCode.Success; + } + + [Command(1)] + // GetSampleCount() -> u32 + public ResultCode GetSampleCount(ServiceCtx context) + { + context.ResponseData.Write(_params.SampleCount); + + return ResultCode.Success; + } + + [Command(2)] + // GetMixBufferCount() -> u32 + public ResultCode GetMixBufferCount(ServiceCtx context) + { + context.ResponseData.Write(_params.MixCount); + + return ResultCode.Success; + } + + [Command(3)] + // GetState() -> u32 + public ResultCode GetState(ServiceCtx context) + { + context.ResponseData.Write((int)_playState); + + Logger.PrintStub(LogClass.ServiceAudio, new { State = Enum.GetName(typeof(PlayState), _playState) }); + + return ResultCode.Success; + } + + private void AudioCallback() + { + _updateEvent.ReadableEvent.Signal(); + } + + private static T[] CreateArray(int size) where T : new() + { + T[] output = new T[size]; + + for (int index = 0; index < size; index++) + { + output[index] = new T(); + } + + return output; + } + + private void InitializeAudioOut() + { + AppendMixedBuffer(0); + AppendMixedBuffer(1); + AppendMixedBuffer(2); + + _audioOut.Start(_track); + } + + [Command(4)] + // RequestUpdateAudioRenderer(buffer) + // -> (buffer, buffer) + public ResultCode RequestUpdateAudioRenderer(ServiceCtx context) + { + long outputPosition = context.Request.ReceiveBuff[0].Position; + long outputSize = context.Request.ReceiveBuff[0].Size; + + MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize); + + long inputPosition = context.Request.SendBuff[0].Position; + + StructReader reader = new StructReader(context.Memory, inputPosition); + StructWriter writer = new StructWriter(context.Memory, outputPosition); + + UpdateDataHeader inputHeader = reader.Read(); + + reader.Read(inputHeader.BehaviorSize); + + MemoryPoolIn[] memoryPoolsIn = reader.Read(inputHeader.MemoryPoolSize); + + for (int index = 0; index < memoryPoolsIn.Length; index++) + { + MemoryPoolIn memoryPool = memoryPoolsIn[index]; + + if (memoryPool.State == MemoryPoolState.RequestAttach) + { + _memoryPools[index].OutStatus.State = MemoryPoolState.Attached; + } + else if (memoryPool.State == MemoryPoolState.RequestDetach) + { + _memoryPools[index].OutStatus.State = MemoryPoolState.Detached; + } + } + + reader.Read(inputHeader.VoiceResourceSize); + + VoiceIn[] voicesIn = reader.Read(inputHeader.VoiceSize); + + for (int index = 0; index < voicesIn.Length; index++) + { + VoiceIn voice = voicesIn[index]; + + VoiceContext voiceCtx = _voices[index]; + + voiceCtx.SetAcquireState(voice.Acquired != 0); + + if (voice.Acquired == 0) + { + continue; + } + + if (voice.FirstUpdate != 0) + { + voiceCtx.AdpcmCtx = GetAdpcmDecoderContext( + voice.AdpcmCoeffsPosition, + voice.AdpcmCoeffsSize); + + voiceCtx.SampleFormat = voice.SampleFormat; + voiceCtx.SampleRate = voice.SampleRate; + voiceCtx.ChannelsCount = voice.ChannelsCount; + + voiceCtx.SetBufferIndex(voice.BaseWaveBufferIndex); + } + + voiceCtx.WaveBuffers[0] = voice.WaveBuffer0; + voiceCtx.WaveBuffers[1] = voice.WaveBuffer1; + voiceCtx.WaveBuffers[2] = voice.WaveBuffer2; + voiceCtx.WaveBuffers[3] = voice.WaveBuffer3; + voiceCtx.Volume = voice.Volume; + voiceCtx.PlayState = voice.PlayState; + } + + UpdateAudio(); + + UpdateDataHeader outputHeader = new UpdateDataHeader(); + + int updateHeaderSize = Marshal.SizeOf(); + + outputHeader.Revision = IAudioRendererManager.RevMagic; + outputHeader.BehaviorSize = 0xb0; + outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10; + outputHeader.VoiceSize = _params.VoiceCount * 0x10; + outputHeader.EffectSize = _params.EffectCount * 0x10; + outputHeader.SinkSize = _params.SinkCount * 0x20; + outputHeader.PerformanceManagerSize = 0x10; + outputHeader.TotalSize = updateHeaderSize + + outputHeader.BehaviorSize + + outputHeader.MemoryPoolSize + + outputHeader.VoiceSize + + outputHeader.EffectSize + + outputHeader.SinkSize + + outputHeader.PerformanceManagerSize; + + writer.Write(outputHeader); + + foreach (MemoryPoolContext memoryPool in _memoryPools) + { + writer.Write(memoryPool.OutStatus); + } + + foreach (VoiceContext voice in _voices) + { + writer.Write(voice.OutStatus); + } + + return ResultCode.Success; + } + + [Command(5)] + // Start() + public ResultCode StartAudioRenderer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAudio); + + _playState = PlayState.Playing; + + return ResultCode.Success; + } + + [Command(6)] + // Stop() + public ResultCode StopAudioRenderer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceAudio); + + _playState = PlayState.Stopped; + + return ResultCode.Success; + } + + [Command(7)] + // QuerySystemEvent() -> handle + public ResultCode QuerySystemEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + private AdpcmDecoderContext GetAdpcmDecoderContext(long position, long size) + { + if (size == 0) + { + return null; + } + + AdpcmDecoderContext context = new AdpcmDecoderContext + { + Coefficients = new short[size >> 1] + }; + + for (int offset = 0; offset < size; offset += 2) + { + context.Coefficients[offset >> 1] = _memory.ReadInt16(position + offset); + } + + return context; + } + + private void UpdateAudio() + { + long[] released = _audioOut.GetReleasedBuffers(_track, 2); + + for (int index = 0; index < released.Length; index++) + { + AppendMixedBuffer(released[index]); + } + } + + private void AppendMixedBuffer(long tag) + { + int[] mixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; + + foreach (VoiceContext voice in _voices) + { + if (!voice.Playing || voice.CurrentWaveBuffer.Size == 0) + { + continue; + } + + int outOffset = 0; + int pendingSamples = MixBufferSamplesCount; + float volume = voice.Volume; + + while (pendingSamples > 0) + { + int[] samples = voice.GetBufferData(_memory, pendingSamples, out int returnedSamples); + + if (returnedSamples == 0) + { + break; + } + + pendingSamples -= returnedSamples; + + for (int offset = 0; offset < samples.Length; offset++) + { + mixBuffer[outOffset++] += (int)(samples[offset] * voice.Volume); + } + } + } + + _audioOut.AppendBuffer(_track, tag, GetFinalBuffer(mixBuffer)); + } + + private unsafe static short[] GetFinalBuffer(int[] buffer) + { + short[] output = new short[buffer.Length]; + + int offset = 0; + + // Perform Saturation using SSE2 if supported + if (Sse2.IsSupported) + { + fixed (int* inptr = buffer) + fixed (short* outptr = output) + { + for (; offset + 32 <= buffer.Length; offset += 32) + { + // Unroll the loop a little to ensure the CPU pipeline + // is always full. + Vector128 block1A = Sse2.LoadVector128(inptr + offset + 0); + Vector128 block1B = Sse2.LoadVector128(inptr + offset + 4); + + Vector128 block2A = Sse2.LoadVector128(inptr + offset + 8); + Vector128 block2B = Sse2.LoadVector128(inptr + offset + 12); + + Vector128 block3A = Sse2.LoadVector128(inptr + offset + 16); + Vector128 block3B = Sse2.LoadVector128(inptr + offset + 20); + + Vector128 block4A = Sse2.LoadVector128(inptr + offset + 24); + Vector128 block4B = Sse2.LoadVector128(inptr + offset + 28); + + Vector128 output1 = Sse2.PackSignedSaturate(block1A, block1B); + Vector128 output2 = Sse2.PackSignedSaturate(block2A, block2B); + Vector128 output3 = Sse2.PackSignedSaturate(block3A, block3B); + Vector128 output4 = Sse2.PackSignedSaturate(block4A, block4B); + + Sse2.Store(outptr + offset + 0, output1); + Sse2.Store(outptr + offset + 8, output2); + Sse2.Store(outptr + offset + 16, output3); + Sse2.Store(outptr + offset + 24, output4); + } + } + } + + // Process left overs + for (; offset < buffer.Length; offset++) + { + output[offset] = DspUtils.Saturate(buffer[offset]); + } + + return output; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _audioOut.CloseTrack(_track); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs new file mode 100644 index 00000000..3f48114c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class MemoryPoolContext + { + public MemoryPoolOut OutStatus; + + public MemoryPoolContext() + { + OutStatus.State = MemoryPoolState.Detached; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs new file mode 100644 index 00000000..936e7f50 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs @@ -0,0 +1,191 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class Resampler + { +#region "LookUp Tables" + private static short[] _curveLut0 = new short[] + { + 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22, + 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48, + 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77, + 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109, + 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147, + 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190, + 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241, + 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300, + 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369, + 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449, + 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541, + 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647, + 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766, + 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901, + 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052, + 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221, + 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407, + 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613, + 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838, + 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083, + 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348, + 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635, + 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942, + 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269, + 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618, + 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987, + 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377, + 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785, + 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213, + 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659, + 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121, + 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600 + }; + + private static short[] _curveLut1 = new short[] + { + -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36, + -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80, + -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128, + -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180, + -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240, + -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307, + -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382, + -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468, + -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563, + -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668, + -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783, + -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907, + -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039, + -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176, + -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317, + -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459, + -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599, + -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732, + -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855, + -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962, + -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049, + -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111, + -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141, + -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133, + -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083, + -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984, + -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830, + -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617, + -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338, + -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990, + -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568, + -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68 + }; + + private static short[] _curveLut2 = new short[] + { + 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42, + 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58, + 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76, + 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98, + 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121, + 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146, + 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174, + 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202, + 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230, + 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258, + 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283, + -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306, + -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325, + -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337, + -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341, + -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336, + -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317, + -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284, + -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234, + -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163, + -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71, + -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47, + -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194, + -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371, + -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583, + -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829, + -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115, + -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442, + -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813, + -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227, + -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688, + -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195 + }; +#endregion + + public static int[] Resample2Ch( + int[] buffer, + int srcSampleRate, + int dstSampleRate, + int samplesCount, + ref int fracPart) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (srcSampleRate <= 0) + { + throw new ArgumentOutOfRangeException(nameof(srcSampleRate)); + } + + if (dstSampleRate <= 0) + { + throw new ArgumentOutOfRangeException(nameof(dstSampleRate)); + } + + double ratio = (double)srcSampleRate / dstSampleRate; + + int newSamplesCount = (int)(samplesCount / ratio); + + int step = (int)(ratio * 0x8000); + + int[] output = new int[newSamplesCount * 2]; + + short[] lut; + + if (step > 0xaaaa) + { + lut = _curveLut0; + } + else if (step <= 0x8000) + { + lut = _curveLut1; + } + else + { + lut = _curveLut2; + } + + int inOffs = 0; + + for (int outOffs = 0; outOffs < output.Length; outOffs += 2) + { + int lutIndex = (fracPart >> 8) * 4; + + int sample0 = buffer[(inOffs + 0) * 2 + 0] * lut[lutIndex + 0] + + buffer[(inOffs + 1) * 2 + 0] * lut[lutIndex + 1] + + buffer[(inOffs + 2) * 2 + 0] * lut[lutIndex + 2] + + buffer[(inOffs + 3) * 2 + 0] * lut[lutIndex + 3]; + + int sample1 = buffer[(inOffs + 0) * 2 + 1] * lut[lutIndex + 0] + + buffer[(inOffs + 1) * 2 + 1] * lut[lutIndex + 1] + + buffer[(inOffs + 2) * 2 + 1] * lut[lutIndex + 2] + + buffer[(inOffs + 3) * 2 + 1] * lut[lutIndex + 3]; + + int newOffset = fracPart + step; + + inOffs += newOffset >> 15; + + fracPart = newOffset & 0x7fff; + + output[outOffs + 0] = sample0 >> 15; + output[outOffs + 1] = sample1 >> 15; + } + + return output; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs new file mode 100644 index 00000000..f3b6995c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class AudioConsts + { + public const int HostSampleRate = 48000; + public const int HostChannelsCount = 2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs new file mode 100644 index 00000000..9772f786 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential)] + struct AudioRendererParameter + { + public int SampleRate; + public int SampleCount; + public int Unknown8; + public int MixCount; + public int VoiceCount; + public int SinkCount; + public int EffectCount; + public int PerformanceManagerCount; + public int VoiceDropEnable; + public int SplitterCount; + public int SplitterDestinationDataCount; + public int Unknown2C; + public int Revision; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs new file mode 100644 index 00000000..953b4ce3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct BehaviorIn + { + public long Unknown0; + public long Unknown8; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs new file mode 100644 index 00000000..d0d8ed9b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 1)] + struct BiquadFilter + { + public byte Enable; + public byte Padding; + public short B0; + public short B1; + public short B2; + public short A1; + public short A2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs new file mode 100644 index 00000000..8dc53929 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 4)] + struct MemoryPoolIn + { + public long Address; + public long Size; + public MemoryPoolState State; + public int Unknown14; + public long Unknown18; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs new file mode 100644 index 00000000..7581e8a7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct MemoryPoolOut + { + public MemoryPoolState State; + public int Unknown14; + public long Unknown18; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs new file mode 100644 index 00000000..a82747b8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + enum MemoryPoolState + { + Invalid = 0, + Unknown = 1, + RequestDetach = 2, + Detached = 3, + RequestAttach = 4, + Attached = 5, + Released = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs new file mode 100644 index 00000000..d63df971 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + enum PlayState : byte + { + Playing = 0, + Stopped = 1, + Paused = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs new file mode 100644 index 00000000..b1f14984 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + struct UpdateDataHeader + { + public int Revision; + public int BehaviorSize; + public int MemoryPoolSize; + public int VoiceSize; + public int VoiceResourceSize; + public int EffectSize; + public int MixeSize; + public int SinkSize; + public int PerformanceManagerSize; + public int Unknown24; + public int Unknown28; + public int Unknown2C; + public int Unknown30; + public int Unknown34; + public int Unknown38; + public int TotalSize; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs new file mode 100644 index 00000000..4871713e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)] + struct VoiceChannelResourceIn + { + // ??? + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs new file mode 100644 index 00000000..dbcd5558 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs @@ -0,0 +1,49 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)] + struct VoiceIn + { + public int VoiceSlot; + public int NodeId; + + public byte FirstUpdate; + public byte Acquired; + + public PlayState PlayState; + + public SampleFormat SampleFormat; + + public int SampleRate; + + public int Priority; + + public int Unknown14; + + public int ChannelsCount; + + public float Pitch; + public float Volume; + + public BiquadFilter BiquadFilter0; + public BiquadFilter BiquadFilter1; + + public int AppendedWaveBuffersCount; + + public int BaseWaveBufferIndex; + + public int Unknown44; + + public long AdpcmCoeffsPosition; + public long AdpcmCoeffsSize; + + public int VoiceDestination; + public int Padding; + + public WaveBuffer WaveBuffer0; + public WaveBuffer WaveBuffer1; + public WaveBuffer WaveBuffer2; + public WaveBuffer WaveBuffer3; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs new file mode 100644 index 00000000..3a295971 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct VoiceOut + { + public long PlayedSamplesCount; + public int PlayedWaveBuffersCount; + public int VoiceDropsCount; //? + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs new file mode 100644 index 00000000..1c0d5630 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)] + struct WaveBuffer + { + public long Position; + public long Size; + public int FirstSampleOffset; + public int LastSampleOffset; + public byte Looping; + public byte LastBuffer; + public short Unknown1A; + public int Unknown1C; + public long AdpcmLoopContextPosition; + public long AdpcmLoopContextSize; + public long Unknown30; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs new file mode 100644 index 00000000..c9fb8502 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs @@ -0,0 +1,199 @@ +using ARMeilleure.Memory; +using Ryujinx.Audio.Adpcm; +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class VoiceContext + { + private bool _acquired; + private bool _bufferReload; + + private int _resamplerFracPart; + + private int _bufferIndex; + private int _offset; + + public int SampleRate { get; set; } + public int ChannelsCount { get; set; } + + public float Volume { get; set; } + + public PlayState PlayState { get; set; } + + public SampleFormat SampleFormat { get; set; } + + public AdpcmDecoderContext AdpcmCtx { get; set; } + + public WaveBuffer[] WaveBuffers { get; } + + public WaveBuffer CurrentWaveBuffer => WaveBuffers[_bufferIndex]; + + private VoiceOut _outStatus; + + public VoiceOut OutStatus => _outStatus; + + private int[] _samples; + + public bool Playing => _acquired && PlayState == PlayState.Playing; + + public VoiceContext() + { + WaveBuffers = new WaveBuffer[4]; + } + + public void SetAcquireState(bool newState) + { + if (_acquired && !newState) + { + // Release. + Reset(); + } + + _acquired = newState; + } + + private void Reset() + { + _bufferReload = true; + + _bufferIndex = 0; + _offset = 0; + + _outStatus.PlayedSamplesCount = 0; + _outStatus.PlayedWaveBuffersCount = 0; + _outStatus.VoiceDropsCount = 0; + } + + public int[] GetBufferData(IMemoryManager memory, int maxSamples, out int samplesCount) + { + if (!Playing) + { + samplesCount = 0; + + return null; + } + + if (_bufferReload) + { + _bufferReload = false; + + UpdateBuffer(memory); + } + + WaveBuffer wb = WaveBuffers[_bufferIndex]; + + int maxSize = _samples.Length - _offset; + + int size = maxSamples * AudioConsts.HostChannelsCount; + + if (size > maxSize) + { + size = maxSize; + } + + int[] output = new int[size]; + + Array.Copy(_samples, _offset, output, 0, size); + + samplesCount = size / AudioConsts.HostChannelsCount; + + _outStatus.PlayedSamplesCount += samplesCount; + + _offset += size; + + if (_offset == _samples.Length) + { + _offset = 0; + + if (wb.Looping == 0) + { + SetBufferIndex((_bufferIndex + 1) & 3); + } + + _outStatus.PlayedWaveBuffersCount++; + + if (wb.LastBuffer != 0) + { + PlayState = PlayState.Paused; + } + } + + return output; + } + + private void UpdateBuffer(IMemoryManager memory) + { + // TODO: Implement conversion for formats other + // than interleaved stereo (2 channels). + // As of now, it assumes that HostChannelsCount == 2. + WaveBuffer wb = WaveBuffers[_bufferIndex]; + + if (wb.Position == 0) + { + _samples = new int[0]; + + return; + } + + if (SampleFormat == SampleFormat.PcmInt16) + { + int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount)); + + _samples = new int[samplesCount * AudioConsts.HostChannelsCount]; + + if (ChannelsCount == 1) + { + for (int index = 0; index < samplesCount; index++) + { + short sample = memory.ReadInt16(wb.Position + index * 2); + + _samples[index * 2 + 0] = sample; + _samples[index * 2 + 1] = sample; + } + } + else + { + for (int index = 0; index < samplesCount * 2; index++) + { + _samples[index] = memory.ReadInt16(wb.Position + index * 2); + } + } + } + else if (SampleFormat == SampleFormat.Adpcm) + { + byte[] buffer = memory.ReadBytes(wb.Position, wb.Size); + + _samples = AdpcmDecoder.Decode(buffer, AdpcmCtx); + } + else + { + throw new InvalidOperationException(); + } + + if (SampleRate != AudioConsts.HostSampleRate) + { + // TODO: We should keep the frames being discarded (see the 4 below) + // on a buffer and include it on the next samples buffer, to allow + // the resampler to do seamless interpolation between wave buffers. + int samplesCount = _samples.Length / AudioConsts.HostChannelsCount; + + samplesCount = Math.Max(samplesCount - 4, 0); + + _samples = Resampler.Resample2Ch( + _samples, + SampleRate, + AudioConsts.HostSampleRate, + samplesCount, + ref _resamplerFracPart); + } + } + + public void SetBufferIndex(int index) + { + _bufferIndex = index & 3; + + _bufferReload = true; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs b/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs new file mode 100644 index 00000000..e23398df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/HardwareOpusDecoderManager/IHardwareOpusDecoder.cs @@ -0,0 +1,81 @@ +using Concentus.Structs; + +namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager +{ + class IHardwareOpusDecoder : IpcService + { + private const int FixedSampleRate = 48000; + + private int _sampleRate; + private int _channelsCount; + + private OpusDecoder _decoder; + + public IHardwareOpusDecoder(int sampleRate, int channelsCount) + { + _sampleRate = sampleRate; + _channelsCount = channelsCount; + + _decoder = new OpusDecoder(FixedSampleRate, channelsCount); + } + + [Command(0)] + // DecodeInterleaved(buffer) -> (u32, u32, buffer) + public ResultCode DecodeInterleaved(ServiceCtx context) + { + long inPosition = context.Request.SendBuff[0].Position; + long inSize = context.Request.SendBuff[0].Size; + + if (inSize < 8) + { + return ResultCode.OpusInvalidInput; + } + + long outPosition = context.Request.ReceiveBuff[0].Position; + long outSize = context.Request.ReceiveBuff[0].Size; + + byte[] opusData = context.Memory.ReadBytes(inPosition, inSize); + + int processed = ((opusData[0] << 24) | + (opusData[1] << 16) | + (opusData[2] << 8) | + (opusData[3] << 0)) + 8; + + if ((uint)processed > (ulong)inSize) + { + return ResultCode.OpusInvalidInput; + } + + short[] pcm = new short[outSize / 2]; + + int frameSize = pcm.Length / (_channelsCount * 2); + + int samples = _decoder.Decode(opusData, 0, opusData.Length, pcm, 0, frameSize); + + foreach (short sample in pcm) + { + context.Memory.WriteInt16(outPosition, sample); + + outPosition += 2; + } + + context.ResponseData.Write(processed); + context.ResponseData.Write(samples); + + return ResultCode.Success; + } + + [Command(4)] + // DecodeInterleavedWithPerf(buffer) -> (u32, u32, u64, buffer) + public ResultCode DecodeInterleavedWithPerf(ServiceCtx context) + { + ResultCode result = DecodeInterleaved(context); + + // TODO: Figure out what this value is. + // According to switchbrew, it is now used. + context.ResponseData.Write(0L); + + return result; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs new file mode 100644 index 00000000..1bd2e31d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioController.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audctl")] + class IAudioController : IpcService + { + public IAudioController(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs new file mode 100644 index 00000000..d8e1f468 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audin:u")] + class IAudioInManager : IpcService + { + public IAudioInManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs new file mode 100644 index 00000000..37d9a8fe --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForApplet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audin:a")] + class IAudioInManagerForApplet : IpcService + { + public IAudioInManagerForApplet(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs new file mode 100644 index 00000000..1a497efb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioInManagerForDebugger.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audin:d")] + class IAudioInManagerForDebugger : IpcService + { + public IAudioInManagerForDebugger(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs new file mode 100644 index 00000000..19ee8067 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManager.cs @@ -0,0 +1,162 @@ +using ARMeilleure.Memory; +using Ryujinx.Audio; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Audio.AudioOutManager; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audout:u")] + class IAudioOutManager : IpcService + { + private const string DefaultAudioOutput = "DeviceOut"; + private const int DefaultSampleRate = 48000; + private const int DefaultChannelsCount = 2; + + public IAudioOutManager(ServiceCtx context) { } + + [Command(0)] + // ListAudioOuts() -> (u32 count, buffer) + public ResultCode ListAudioOuts(ServiceCtx context) + { + return ListAudioOutsImpl( + context, + context.Request.ReceiveBuff[0].Position, + context.Request.ReceiveBuff[0].Size); + } + + [Command(1)] + // OpenAudioOut(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle, buffer name_in) + // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name_out) + public ResultCode OpenAudioOut(ServiceCtx context) + { + return OpenAudioOutImpl( + context, + context.Request.SendBuff[0].Position, + context.Request.SendBuff[0].Size, + context.Request.ReceiveBuff[0].Position, + context.Request.ReceiveBuff[0].Size); + } + + [Command(2)] // 3.0.0+ + // ListAudioOutsAuto() -> (u32 count, buffer) + public ResultCode ListAudioOutsAuto(ServiceCtx context) + { + (long recvPosition, long recvSize) = context.Request.GetBufferType0x22(); + + return ListAudioOutsImpl(context, recvPosition, recvSize); + } + + [Command(3)] // 3.0.0+ + // OpenAudioOutAuto(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle, buffer) + // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object, buffer name_out) + public ResultCode OpenAudioOutAuto(ServiceCtx context) + { + (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); + (long recvPosition, long recvSize) = context.Request.GetBufferType0x22(); + + return OpenAudioOutImpl( + context, + sendPosition, + sendSize, + recvPosition, + recvSize); + } + + private ResultCode ListAudioOutsImpl(ServiceCtx context, long position, long size) + { + int nameCount = 0; + + byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0"); + + if ((ulong)deviceNameBuffer.Length <= (ulong)size) + { + context.Memory.WriteBytes(position, deviceNameBuffer); + + nameCount++; + } + else + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!"); + } + + context.ResponseData.Write(nameCount); + + return ResultCode.Success; + } + + private ResultCode OpenAudioOutImpl(ServiceCtx context, long sendPosition, long sendSize, long receivePosition, long receiveSize) + { + string deviceName = MemoryHelper.ReadAsciiString( + context.Memory, + sendPosition, + sendSize); + + if (deviceName == string.Empty) + { + deviceName = DefaultAudioOutput; + } + + if (deviceName != DefaultAudioOutput) + { + Logger.PrintWarning(LogClass.Audio, "Invalid device name!"); + + return ResultCode.DeviceNotFound; + } + + byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(deviceName + "\0"); + + if ((ulong)deviceNameBuffer.Length <= (ulong)receiveSize) + { + context.Memory.WriteBytes(receivePosition, deviceNameBuffer); + } + else + { + Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {receiveSize} too small!"); + } + + int sampleRate = context.RequestData.ReadInt32(); + int channels = context.RequestData.ReadInt32(); + + if (sampleRate == 0) + { + sampleRate = DefaultSampleRate; + } + + if (sampleRate != DefaultSampleRate) + { + Logger.PrintWarning(LogClass.Audio, "Invalid sample rate!"); + + return ResultCode.UnsupportedSampleRate; + } + + channels = (ushort)channels; + + if (channels == 0) + { + channels = DefaultChannelsCount; + } + + KEvent releaseEvent = new KEvent(context.Device.System); + + ReleaseCallback callback = () => + { + releaseEvent.ReadableEvent.Signal(); + }; + + IAalOutput audioOut = context.Device.AudioOut; + + int track = audioOut.OpenTrack(sampleRate, channels, callback); + + MakeObject(context, new IAudioOut(audioOut, releaseEvent, track)); + + context.ResponseData.Write(sampleRate); + context.ResponseData.Write(channels); + context.ResponseData.Write((int)SampleFormat.PcmInt16); + context.ResponseData.Write((int)PlaybackState.Stopped); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs new file mode 100644 index 00000000..4b41b0cf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForApplet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audout:a")] + class IAudioOutManagerForApplet : IpcService + { + public IAudioOutManagerForApplet(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs new file mode 100644 index 00000000..41cde972 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioOutManagerForDebugger.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audout:d")] + class IAudioOutManagerForDebugger : IpcService + { + public IAudioOutManagerForDebugger(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs new file mode 100644 index 00000000..de1c35b5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs @@ -0,0 +1,193 @@ +using Ryujinx.Audio; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager; +using Ryujinx.HLE.Utilities; + +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audren:u")] + class IAudioRendererManager : IpcService + { + private const int Rev0Magic = ('R' << 0) | + ('E' << 8) | + ('V' << 16) | + ('0' << 24); + + private const int Rev = 5; + + public const int RevMagic = Rev0Magic + (Rev << 24); + + public IAudioRendererManager(ServiceCtx context) { } + + [Command(0)] + // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle, handle) + // -> object + public ResultCode OpenAudioRenderer(ServiceCtx context) + { + IAalOutput audioOut = context.Device.AudioOut; + + AudioRendererParameter Params = GetAudioRendererParameter(context); + + MakeObject(context, new IAudioRenderer( + context.Device.System, + context.Memory, + audioOut, + Params)); + + return ResultCode.Success; + } + + [Command(1)] + // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64 + public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context) + { + AudioRendererParameter Params = GetAudioRendererParameter(context); + + int revision = (Params.Revision - Rev0Magic) >> 24; + + if (revision <= Rev) + { + bool isSplitterSupported = revision >= 3; + bool isVariadicCommandBufferSizeSupported = revision >= 5; + + long size; + + size = IntUtils.AlignUp(Params.Unknown8 * 4, 64); + size += Params.MixCount * 0x400; + size += (Params.MixCount + 1) * 0x940; + size += Params.VoiceCount * 0x3F0; + size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16); + size += IntUtils.AlignUp(Params.VoiceCount * 8, 16); + size += IntUtils.AlignUp( + ((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) * + (Params.Unknown8 + 6), 64); + size += (Params.SinkCount + Params.MixCount) * 0x2C0; + size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50; + + if (isSplitterSupported) + { + size += IntUtils.AlignUp(( + NodeStatesGetWorkBufferSize(Params.MixCount + 1) + + EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16); + + size += Params.SplitterDestinationDataCount * 0xE0; + size += Params.SplitterCount * 0x20; + size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16); + } + + size = Params.EffectCount * 0x4C0 + + Params.SinkCount * 0x170 + + Params.VoiceCount * 0x100 + + IntUtils.AlignUp(size, 64) + 0x40; + + if (Params.PerformanceManagerCount >= 1) + { + size += (((Params.EffectCount + + Params.SinkCount + + Params.VoiceCount + + Params.MixCount + 1) * 16 + 0x658) * + (Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL; + } + + if (isVariadicCommandBufferSizeSupported) + { + size += Params.EffectCount * 0x840 + + Params.MixCount * 0x5A38 + + Params.SinkCount * 0x148 + + Params.SplitterDestinationDataCount * 0x540 + + Params.VoiceCount * (Params.SplitterCount * 0x68 + 0x2E0) + + ((Params.VoiceCount + Params.MixCount + Params.EffectCount + Params.SinkCount + 0x65) << 6) + 0x3F8 + 0x7E; + } + else + { + size += 0x1807E; + } + + size = size & ~0xFFFL; + + context.ResponseData.Write(size); + + Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}."); + + return ResultCode.Success; + } + else + { + context.ResponseData.Write(0L); + + Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!"); + + return ResultCode.UnsupportedRevision; + } + } + + private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context) + { + AudioRendererParameter Params = new AudioRendererParameter + { + SampleRate = context.RequestData.ReadInt32(), + SampleCount = context.RequestData.ReadInt32(), + Unknown8 = context.RequestData.ReadInt32(), + MixCount = context.RequestData.ReadInt32(), + VoiceCount = context.RequestData.ReadInt32(), + SinkCount = context.RequestData.ReadInt32(), + EffectCount = context.RequestData.ReadInt32(), + PerformanceManagerCount = context.RequestData.ReadInt32(), + VoiceDropEnable = context.RequestData.ReadInt32(), + SplitterCount = context.RequestData.ReadInt32(), + SplitterDestinationDataCount = context.RequestData.ReadInt32(), + Unknown2C = context.RequestData.ReadInt32(), + Revision = context.RequestData.ReadInt32() + }; + + return Params; + } + + private static int NodeStatesGetWorkBufferSize(int value) + { + int result = IntUtils.AlignUp(value, 64); + + if (result < 0) + { + result |= 7; + } + + return 4 * (value * value) + 0x12 * value + 2 * (result / 8); + } + + private static int EdgeMatrixGetWorkBufferSize(int value) + { + int result = IntUtils.AlignUp(value * value, 64); + + if (result < 0) + { + result |= 7; + } + + return result / 8; + } + + [Command(2)] + // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object + public ResultCode GetAudioDeviceService(ServiceCtx context) + { + long appletResourceUserId = context.RequestData.ReadInt64(); + + MakeObject(context, new IAudioDevice(context.Device.System)); + + return ResultCode.Success; + } + + [Command(4)] // 4.0.0+ + // GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object + public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context) + { + long appletResourceUserId = context.RequestData.ReadInt64(); + int revisionInfo = context.RequestData.ReadInt32(); + + Logger.PrintStub(LogClass.ServiceAudio, new { appletResourceUserId, revisionInfo }); + + return GetAudioDeviceService(context); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs new file mode 100644 index 00000000..ca5768cc --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForApplet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audren:a")] + class IAudioRendererManagerForApplet : IpcService + { + public IAudioRendererManagerForApplet(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs new file mode 100644 index 00000000..a970ae45 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManagerForDebugger.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audren:d")] + class IAudioRendererManagerForDebugger : IpcService + { + public IAudioRendererManagerForDebugger(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs new file mode 100644 index 00000000..59e3ad09 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioSnoopManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("auddev")] // 6.0.0+ + class IAudioSnoopManager : IpcService + { + public IAudioSnoopManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs new file mode 100644 index 00000000..01435008 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audrec:u")] + class IFinalOutputRecorderManager : IpcService + { + public IFinalOutputRecorderManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs new file mode 100644 index 00000000..d8fd270d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForApplet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audrec:a")] + class IFinalOutputRecorderManagerForApplet : IpcService + { + public IFinalOutputRecorderManagerForApplet(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs new file mode 100644 index 00000000..a8ec51ee --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IFinalOutputRecorderManagerForDebugger.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("audrec:d")] + class IFinalOutputRecorderManagerForDebugger : IpcService + { + public IFinalOutputRecorderManagerForDebugger(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs new file mode 100644 index 00000000..ed40cdad --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs @@ -0,0 +1,65 @@ +using Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager; + +namespace Ryujinx.HLE.HOS.Services.Audio +{ + [Service("hwopus")] + class IHardwareOpusDecoderManager : IpcService + { + public IHardwareOpusDecoderManager(ServiceCtx context) { } + + [Command(0)] + // Initialize(bytes<8, 4>, u32, handle) -> object + public ResultCode Initialize(ServiceCtx context) + { + int sampleRate = context.RequestData.ReadInt32(); + int channelsCount = context.RequestData.ReadInt32(); + + MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount)); + + return ResultCode.Success; + } + + [Command(1)] + // GetWorkBufferSize(bytes<8, 4>) -> u32 + public ResultCode GetWorkBufferSize(ServiceCtx context) + { + // Note: The sample rate is ignored because it is fixed to 48KHz. + int sampleRate = context.RequestData.ReadInt32(); + int channelsCount = context.RequestData.ReadInt32(); + + context.ResponseData.Write(GetOpusDecoderSize(channelsCount)); + + return ResultCode.Success; + } + + private static int GetOpusDecoderSize(int channelsCount) + { + const int silkDecoderSize = 0x2198; + + if (channelsCount < 1 || channelsCount > 2) + { + return 0; + } + + int celtDecoderSize = GetCeltDecoderSize(channelsCount); + + int opusDecoderSize = (channelsCount * 0x800 + 0x4807) & -0x800 | 0x50; + + return opusDecoderSize + silkDecoderSize + celtDecoderSize; + } + + private static int GetCeltDecoderSize(int channelsCount) + { + const int decodeBufferSize = 0x2030; + const int celtDecoderSize = 0x58; + const int celtSigSize = 0x4; + const int overlap = 120; + const int eBandsCount = 21; + + return (decodeBufferSize + overlap * 4) * channelsCount + + eBandsCount * 16 + + celtDecoderSize + + celtSigSize; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs new file mode 100644 index 00000000..5bba3582 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/ResultCode.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + enum ResultCode + { + ModuleId = 153, + ErrorCodeShift = 9, + + Success = 0, + + DeviceNotFound = (1 << ErrorCodeShift) | ModuleId, + UnsupportedRevision = (2 << ErrorCodeShift) | ModuleId, + UnsupportedSampleRate = (3 << ErrorCodeShift) | ModuleId, + OpusInvalidInput = (6 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/Types/SampleFormat.cs b/Ryujinx.HLE/HOS/Services/Audio/Types/SampleFormat.cs new file mode 100644 index 00000000..654436e4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/Types/SampleFormat.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Audio +{ + enum SampleFormat : byte + { + Invalid = 0, + PcmInt8 = 1, + PcmInt16 = 2, + PcmInt24 = 3, + PcmInt32 = 4, + PcmFloat = 5, + Adpcm = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs deleted file mode 100644 index 030f9110..00000000 --- a/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Glue; - -namespace Ryujinx.HLE.HOS.Services.Bcat -{ - class IBcatService : IpcService - { - public IBcatService(ApplicationLaunchProperty applicationLaunchProperty) { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs deleted file mode 100644 index 1c9aed11..00000000 --- a/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Glue; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Bcat -{ - class IDeliveryCacheStorageService : IpcService - { - private const int DeliveryCacheDirectoriesLimit = 100; - private const int DeliveryCacheDirectoryNameLength = 32; - - private string[] _deliveryCacheDirectories = new string[0]; - - public IDeliveryCacheStorageService(ServiceCtx context, ApplicationLaunchProperty applicationLaunchProperty) - { - // TODO: Read directories.meta file from the save data (loaded in IServiceCreator) in _deliveryCacheDirectories. - } - - [Command(10)] - // EnumerateDeliveryCacheDirectory() -> (u32, buffer) - public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context) - { - long outputPosition = context.Request.ReceiveBuff[0].Position; - long outputSize = context.Request.ReceiveBuff[0].Size; - - for (int index = 0; index < _deliveryCacheDirectories.Length; index++) - { - if (index == DeliveryCacheDirectoriesLimit - 1) - { - break; - } - - byte[] directoryNameBuffer = Encoding.ASCII.GetBytes(_deliveryCacheDirectories[index]); - - Array.Resize(ref directoryNameBuffer, DeliveryCacheDirectoryNameLength); - - directoryNameBuffer[DeliveryCacheDirectoryNameLength - 1] = 0x00; - - context.Memory.WriteBytes(outputPosition + index * DeliveryCacheDirectoryNameLength, directoryNameBuffer); - } - - context.ResponseData.Write(_deliveryCacheDirectories.Length); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs index 4e9d3656..ec34f540 100644 --- a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.HOS.Services.Glue; +using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator; +using Ryujinx.HLE.HOS.Services.Arp; namespace Ryujinx.HLE.HOS.Services.Bcat { diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IBcatService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IBcatService.cs new file mode 100644 index 00000000..1b32756a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IBcatService.cs @@ -0,0 +1,9 @@ +using Ryujinx.HLE.HOS.Services.Arp; + +namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator +{ + class IBcatService : IpcService + { + public IBcatService(ApplicationLaunchProperty applicationLaunchProperty) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs new file mode 100644 index 00000000..cad44370 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs @@ -0,0 +1,47 @@ +using Ryujinx.HLE.HOS.Services.Arp; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator +{ + class IDeliveryCacheStorageService : IpcService + { + private const int DeliveryCacheDirectoriesLimit = 100; + private const int DeliveryCacheDirectoryNameLength = 32; + + private string[] _deliveryCacheDirectories = new string[0]; + + public IDeliveryCacheStorageService(ServiceCtx context, ApplicationLaunchProperty applicationLaunchProperty) + { + // TODO: Read directories.meta file from the save data (loaded in IServiceCreator) in _deliveryCacheDirectories. + } + + [Command(10)] + // EnumerateDeliveryCacheDirectory() -> (u32, buffer) + public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context) + { + long outputPosition = context.Request.ReceiveBuff[0].Position; + long outputSize = context.Request.ReceiveBuff[0].Size; + + for (int index = 0; index < _deliveryCacheDirectories.Length; index++) + { + if (index == DeliveryCacheDirectoriesLimit - 1) + { + break; + } + + byte[] directoryNameBuffer = Encoding.ASCII.GetBytes(_deliveryCacheDirectories[index]); + + Array.Resize(ref directoryNameBuffer, DeliveryCacheDirectoryNameLength); + + directoryNameBuffer[DeliveryCacheDirectoryNameLength - 1] = 0x00; + + context.Memory.WriteBytes(outputPosition + index * DeliveryCacheDirectoryNameLength, directoryNameBuffer); + } + + context.ResponseData.Write(_deliveryCacheDirectories.Length); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bgtc/IStateControlService.cs b/Ryujinx.HLE/HOS/Services/Bgtc/IStateControlService.cs new file mode 100644 index 00000000..4926d4d8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bgtc/IStateControlService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Bgct +{ + [Service("bgtc:sc")] + class IStateControlService : IpcService + { + public IStateControlService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bgtc/ITaskService.cs b/Ryujinx.HLE/HOS/Services/Bgtc/ITaskService.cs new file mode 100644 index 00000000..a032c380 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bgtc/ITaskService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Bgct +{ + [Service("bgtc:t")] + class ITaskService : IpcService + { + public ITaskService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothDriver/BluetoothEventManager.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothDriver/BluetoothEventManager.cs new file mode 100644 index 00000000..81f4a7d2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothDriver/BluetoothEventManager.cs @@ -0,0 +1,25 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Bluetooth.BluetoothDriver +{ + static class BluetoothEventManager + { + public static KEvent InitializeBleDebugEvent; + public static int InitializeBleDebugEventHandle; + + public static KEvent UnknownBleDebugEvent; + public static int UnknownBleDebugEventHandle; + + public static KEvent RegisterBleDebugEvent; + public static int RegisterBleDebugEventHandle; + + public static KEvent InitializeBleEvent; + public static int InitializeBleEventHandle; + + public static KEvent UnknownBleEvent; + public static int UnknownBleEventHandle; + + public static KEvent RegisterBleEvent; + public static int RegisterBleEventHandle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothEventManager.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothEventManager.cs deleted file mode 100644 index 9b7ca4c1..00000000 --- a/Ryujinx.HLE/HOS/Services/Bluetooth/BluetoothEventManager.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Bluetooth -{ - static class BluetoothEventManager - { - public static KEvent InitializeBleDebugEvent; - public static int InitializeBleDebugEventHandle; - - public static KEvent UnknownBleDebugEvent; - public static int UnknownBleDebugEventHandle; - - public static KEvent RegisterBleDebugEvent; - public static int RegisterBleDebugEventHandle; - - public static KEvent InitializeBleEvent; - public static int InitializeBleEventHandle; - - public static KEvent UnknownBleEvent; - public static int UnknownBleEventHandle; - - public static KEvent RegisterBleEvent; - public static int RegisterBleEventHandle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs index 4cee67cd..fc20ec30 100644 --- a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs +++ b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Set; +using Ryujinx.HLE.HOS.Services.Bluetooth.BluetoothDriver; +using Ryujinx.HLE.HOS.Services.Settings; using System; namespace Ryujinx.HLE.HOS.Services.Bluetooth diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothUser.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothUser.cs index d070e18f..c5693c57 100644 --- a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothUser.cs +++ b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothUser.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Services.Set; +using Ryujinx.HLE.HOS.Services.Bluetooth.BluetoothDriver; +using Ryujinx.HLE.HOS.Services.Settings; namespace Ryujinx.HLE.HOS.Services.Bluetooth { diff --git a/Ryujinx.HLE/HOS/Services/Bpc/IRtcManager.cs b/Ryujinx.HLE/HOS/Services/Bpc/IRtcManager.cs deleted file mode 100644 index 5ff9410a..00000000 --- a/Ryujinx.HLE/HOS/Services/Bpc/IRtcManager.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Bpc -{ - [Service("bpc:r")] - class IRtcManager : IpcService - { - public IRtcManager(ServiceCtx context) { } - - [Command(0)] - // GetRtcTime() -> u64 - public ResultCode GetRtcTime(ServiceCtx context) - { - ResultCode result = GetExternalRtcValue(out ulong rtcValue); - - if (result == ResultCode.Success) - { - context.ResponseData.Write(rtcValue); - } - - return result; - } - - public static ResultCode GetExternalRtcValue(out ulong rtcValue) - { - // TODO: emulate MAX77620/MAX77812 RTC - DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - rtcValue = (ulong)(DateTime.Now.ToUniversalTime() - unixEpoch).TotalSeconds; - - return ResultCode.Success; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Bsd/BsdIoctl.cs b/Ryujinx.HLE/HOS/Services/Bsd/BsdIoctl.cs deleted file mode 100644 index 76713b25..00000000 --- a/Ryujinx.HLE/HOS/Services/Bsd/BsdIoctl.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Bsd -{ - enum BsdIoctl - { - AtMark = 0x40047307 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs b/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs deleted file mode 100644 index 2786da13..00000000 --- a/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Net.Sockets; - -namespace Ryujinx.HLE.HOS.Services.Bsd -{ - class BsdSocket - { - public int Family; - public int Type; - public int Protocol; - - public Socket Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs b/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs deleted file mode 100644 index 03399372..00000000 --- a/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs +++ /dev/null @@ -1,1180 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.Utilities; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Bsd -{ - [Service("bsd:s", true)] - [Service("bsd:u", false)] - class IClient : IpcService - { - private static Dictionary _errorMap = new Dictionary - { - // WSAEINTR - {WsaError.WSAEINTR, LinuxError.EINTR}, - // WSAEWOULDBLOCK - {WsaError.WSAEWOULDBLOCK, LinuxError.EWOULDBLOCK}, - // WSAEINPROGRESS - {WsaError.WSAEINPROGRESS, LinuxError.EINPROGRESS}, - // WSAEALREADY - {WsaError.WSAEALREADY, LinuxError.EALREADY}, - // WSAENOTSOCK - {WsaError.WSAENOTSOCK, LinuxError.ENOTSOCK}, - // WSAEDESTADDRREQ - {WsaError.WSAEDESTADDRREQ, LinuxError.EDESTADDRREQ}, - // WSAEMSGSIZE - {WsaError.WSAEMSGSIZE, LinuxError.EMSGSIZE}, - // WSAEPROTOTYPE - {WsaError.WSAEPROTOTYPE, LinuxError.EPROTOTYPE}, - // WSAENOPROTOOPT - {WsaError.WSAENOPROTOOPT, LinuxError.ENOPROTOOPT}, - // WSAEPROTONOSUPPORT - {WsaError.WSAEPROTONOSUPPORT, LinuxError.EPROTONOSUPPORT}, - // WSAESOCKTNOSUPPORT - {WsaError.WSAESOCKTNOSUPPORT, LinuxError.ESOCKTNOSUPPORT}, - // WSAEOPNOTSUPP - {WsaError.WSAEOPNOTSUPP, LinuxError.EOPNOTSUPP}, - // WSAEPFNOSUPPORT - {WsaError.WSAEPFNOSUPPORT, LinuxError.EPFNOSUPPORT}, - // WSAEAFNOSUPPORT - {WsaError.WSAEAFNOSUPPORT, LinuxError.EAFNOSUPPORT}, - // WSAEADDRINUSE - {WsaError.WSAEADDRINUSE, LinuxError.EADDRINUSE}, - // WSAEADDRNOTAVAIL - {WsaError.WSAEADDRNOTAVAIL, LinuxError.EADDRNOTAVAIL}, - // WSAENETDOWN - {WsaError.WSAENETDOWN, LinuxError.ENETDOWN}, - // WSAENETUNREACH - {WsaError.WSAENETUNREACH, LinuxError.ENETUNREACH}, - // WSAENETRESET - {WsaError.WSAENETRESET, LinuxError.ENETRESET}, - // WSAECONNABORTED - {WsaError.WSAECONNABORTED, LinuxError.ECONNABORTED}, - // WSAECONNRESET - {WsaError.WSAECONNRESET, LinuxError.ECONNRESET}, - // WSAENOBUFS - {WsaError.WSAENOBUFS, LinuxError.ENOBUFS}, - // WSAEISCONN - {WsaError.WSAEISCONN, LinuxError.EISCONN}, - // WSAENOTCONN - {WsaError.WSAENOTCONN, LinuxError.ENOTCONN}, - // WSAESHUTDOWN - {WsaError.WSAESHUTDOWN, LinuxError.ESHUTDOWN}, - // WSAETOOMANYREFS - {WsaError.WSAETOOMANYREFS, LinuxError.ETOOMANYREFS}, - // WSAETIMEDOUT - {WsaError.WSAETIMEDOUT, LinuxError.ETIMEDOUT}, - // WSAECONNREFUSED - {WsaError.WSAECONNREFUSED, LinuxError.ECONNREFUSED}, - // WSAELOOP - {WsaError.WSAELOOP, LinuxError.ELOOP}, - // WSAENAMETOOLONG - {WsaError.WSAENAMETOOLONG, LinuxError.ENAMETOOLONG}, - // WSAEHOSTDOWN - {WsaError.WSAEHOSTDOWN, LinuxError.EHOSTDOWN}, - // WSAEHOSTUNREACH - {WsaError.WSAEHOSTUNREACH, LinuxError.EHOSTUNREACH}, - // WSAENOTEMPTY - {WsaError.WSAENOTEMPTY, LinuxError.ENOTEMPTY}, - // WSAEUSERS - {WsaError.WSAEUSERS, LinuxError.EUSERS}, - // WSAEDQUOT - {WsaError.WSAEDQUOT, LinuxError.EDQUOT}, - // WSAESTALE - {WsaError.WSAESTALE, LinuxError.ESTALE}, - // WSAEREMOTE - {WsaError.WSAEREMOTE, LinuxError.EREMOTE}, - // WSAEINVAL - {WsaError.WSAEINVAL, LinuxError.EINVAL}, - // WSAEFAULT - {WsaError.WSAEFAULT, LinuxError.EFAULT}, - // NOERROR - {0, 0} - }; - - private bool _isPrivileged; - - private List _sockets = new List(); - - public IClient(ServiceCtx context, bool isPrivileged) - { - _isPrivileged = isPrivileged; - } - - private LinuxError ConvertError(WsaError errorCode) - { - if (!_errorMap.TryGetValue(errorCode, out LinuxError errno)) - { - errno = (LinuxError)errorCode; - } - - return errno; - } - - private ResultCode WriteWinSock2Error(ServiceCtx context, WsaError errorCode) - { - return WriteBsdResult(context, -1, ConvertError(errorCode)); - } - - private ResultCode WriteBsdResult(ServiceCtx context, int result, LinuxError errorCode = 0) - { - if (errorCode != LinuxError.SUCCESS) - { - result = -1; - } - - context.ResponseData.Write(result); - context.ResponseData.Write((int)errorCode); - - return ResultCode.Success; - } - - private BsdSocket RetrieveSocket(int socketFd) - { - if (socketFd >= 0 && _sockets.Count > socketFd) - { - return _sockets[socketFd]; - } - - return null; - } - - private LinuxError SetResultErrno(Socket socket, int result) - { - return result == 0 && !socket.Blocking ? LinuxError.EWOULDBLOCK : LinuxError.SUCCESS; - } - - private AddressFamily ConvertFromBsd(int domain) - { - if (domain == 2) - { - return AddressFamily.InterNetwork; - } - - // FIXME: AF_ROUTE ignored, is that really needed? - return AddressFamily.Unknown; - } - - private ResultCode SocketInternal(ServiceCtx context, bool exempt) - { - AddressFamily domain = (AddressFamily)context.RequestData.ReadInt32(); - SocketType type = (SocketType)context.RequestData.ReadInt32(); - ProtocolType protocol = (ProtocolType)context.RequestData.ReadInt32(); - - if (domain == AddressFamily.Unknown) - { - return WriteBsdResult(context, -1, LinuxError.EPROTONOSUPPORT); - } - else if ((type == SocketType.Seqpacket || type == SocketType.Raw) && !_isPrivileged) - { - if (domain != AddressFamily.InterNetwork || type != SocketType.Raw || protocol != ProtocolType.Icmp) - { - return WriteBsdResult(context, -1, LinuxError.ENOENT); - } - } - - BsdSocket newBsdSocket = new BsdSocket - { - Family = (int)domain, - Type = (int)type, - Protocol = (int)protocol, - Handle = new Socket(domain, type, protocol) - }; - - _sockets.Add(newBsdSocket); - - if (exempt) - { - newBsdSocket.Handle.Disconnect(true); - } - - return WriteBsdResult(context, _sockets.Count - 1); - } - - private IPEndPoint ParseSockAddr(ServiceCtx context, long bufferPosition, long bufferSize) - { - int size = context.Memory.ReadByte(bufferPosition); - int family = context.Memory.ReadByte(bufferPosition + 1); - int port = EndianSwap.Swap16(context.Memory.ReadUInt16(bufferPosition + 2)); - - byte[] rawIp = context.Memory.ReadBytes(bufferPosition + 4, 4); - - return new IPEndPoint(new IPAddress(rawIp), port); - } - - private void WriteSockAddr(ServiceCtx context, long bufferPosition, IPEndPoint endPoint) - { - context.Memory.WriteByte(bufferPosition, 0); - context.Memory.WriteByte(bufferPosition + 1, (byte)endPoint.AddressFamily); - context.Memory.WriteUInt16(bufferPosition + 2, EndianSwap.Swap16((ushort)endPoint.Port)); - context.Memory.WriteBytes(bufferPosition + 4, endPoint.Address.GetAddressBytes()); - } - - private void WriteSockAddr(ServiceCtx context, long bufferPosition, BsdSocket socket, bool isRemote) - { - IPEndPoint endPoint = (isRemote ? socket.Handle.RemoteEndPoint : socket.Handle.LocalEndPoint) as IPEndPoint; - - WriteSockAddr(context, bufferPosition, endPoint); - } - - [Command(0)] - // Initialize(nn::socket::BsdBufferConfig config, u64 pid, u64 transferMemorySize, KObject, pid) -> u32 bsd_errno - public ResultCode RegisterClient(ServiceCtx context) - { - /* - typedef struct { - u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0. - u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed). - u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed). - u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value. - u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value. - u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes). - u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes). - u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8). - } BsdBufferConfig; - */ - - // bsd_error - context.ResponseData.Write(0); - - Logger.PrintStub(LogClass.ServiceBsd); - - return ResultCode.Success; - } - - [Command(1)] - // StartMonitoring(u64, pid) - public ResultCode StartMonitoring(ServiceCtx context) - { - ulong unknown0 = context.RequestData.ReadUInt64(); - - Logger.PrintStub(LogClass.ServiceBsd, new { unknown0 }); - - return ResultCode.Success; - } - - [Command(2)] - // Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) - public ResultCode Socket(ServiceCtx context) - { - return SocketInternal(context, false); - } - - [Command(3)] - // SocketExempt(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) - public ResultCode SocketExempt(ServiceCtx context) - { - return SocketInternal(context, true); - } - - [Command(4)] - // Open(u32 flags, array path) -> (i32 ret, u32 bsd_errno) - public ResultCode Open(ServiceCtx context) - { - (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(); - - int flags = context.RequestData.ReadInt32(); - - byte[] rawPath = context.Memory.ReadBytes(bufferPosition, bufferSize); - string path = Encoding.ASCII.GetString(rawPath); - - WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - - Logger.PrintStub(LogClass.ServiceBsd, new { path, flags }); - - return ResultCode.Success; - } - - [Command(5)] - // Select(u32 nfds, nn::socket::timeout timeout, buffer readfds_in, buffer writefds_in, buffer errorfds_in) -> (i32 ret, u32 bsd_errno, buffer readfds_out, buffer writefds_out, buffer errorfds_out) - public ResultCode Select(ServiceCtx context) - { - WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - - Logger.PrintStub(LogClass.ServiceBsd); - - return ResultCode.Success; - } - - [Command(6)] - // Poll(u32 nfds, u32 timeout, buffer fds) -> (i32 ret, u32 bsd_errno, buffer) - public ResultCode Poll(ServiceCtx context) - { - int fdsCount = context.RequestData.ReadInt32(); - int timeout = context.RequestData.ReadInt32(); - - (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(); - - - if (timeout < -1 || fdsCount < 0 || (fdsCount * 8) > bufferSize) - { - return WriteBsdResult(context, -1, LinuxError.EINVAL); - } - - PollEvent[] events = new PollEvent[fdsCount]; - - for (int i = 0; i < fdsCount; i++) - { - int socketFd = context.Memory.ReadInt32(bufferPosition + i * 8); - - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket == null) - { - return WriteBsdResult(context, -1, LinuxError.EBADF);} - - PollEvent.EventTypeMask inputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 4); - PollEvent.EventTypeMask outputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 6); - - events[i] = new PollEvent(socketFd, socket, inputEvents, outputEvents); - } - - List readEvents = new List(); - List writeEvents = new List(); - List errorEvents = new List(); - - foreach (PollEvent Event in events) - { - bool isValidEvent = false; - - if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) - { - readEvents.Add(Event.Socket.Handle); - errorEvents.Add(Event.Socket.Handle); - - isValidEvent = true; - } - - if ((Event.InputEvents & PollEvent.EventTypeMask.UrgentInput) != 0) - { - readEvents.Add(Event.Socket.Handle); - errorEvents.Add(Event.Socket.Handle); - - isValidEvent = true; - } - - if ((Event.InputEvents & PollEvent.EventTypeMask.Output) != 0) - { - writeEvents.Add(Event.Socket.Handle); - errorEvents.Add(Event.Socket.Handle); - - isValidEvent = true; - } - - if ((Event.InputEvents & PollEvent.EventTypeMask.Error) != 0) - { - errorEvents.Add(Event.Socket.Handle); - isValidEvent = true; - } - - if (!isValidEvent) - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Poll input event type: {Event.InputEvents}"); - return WriteBsdResult(context, -1, LinuxError.EINVAL); - } - } - - try - { - System.Net.Sockets.Socket.Select(readEvents, writeEvents, errorEvents, timeout); - } - catch (SocketException exception) - { - return WriteWinSock2Error(context, (WsaError)exception.ErrorCode); - } - - for (int i = 0; i < fdsCount; i++) - { - PollEvent Event = events[i]; - context.Memory.WriteInt32(bufferPosition + i * 8, Event.SocketFd); - context.Memory.WriteInt16(bufferPosition + i * 8 + 4, (short)Event.InputEvents); - - PollEvent.EventTypeMask outputEvents = 0; - - Socket socket = Event.Socket.Handle; - - if (errorEvents.Contains(socket)) - { - outputEvents |= PollEvent.EventTypeMask.Error; - - if (!socket.Connected || !socket.IsBound) - { - outputEvents |= PollEvent.EventTypeMask.Disconnected; - } - } - - if (readEvents.Contains(socket)) - { - if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) - { - outputEvents |= PollEvent.EventTypeMask.Input; - } - } - - if (writeEvents.Contains(socket)) - { - outputEvents |= PollEvent.EventTypeMask.Output; - } - - context.Memory.WriteInt16(bufferPosition + i * 8 + 6, (short)outputEvents); - } - - return WriteBsdResult(context, readEvents.Count + writeEvents.Count + errorEvents.Count, LinuxError.SUCCESS); - } - - [Command(7)] - // Sysctl(buffer, buffer) -> (i32 ret, u32 bsd_errno, u32, buffer) - public ResultCode Sysctl(ServiceCtx context) - { - WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - - Logger.PrintStub(LogClass.ServiceBsd); - - return ResultCode.Success; - } - - [Command(8)] - // Recv(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, array message) - public ResultCode Recv(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); - - (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0 - && (socketFlags & SocketFlags.Peek) == 0) - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}"); - return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - } - - byte[] receivedBuffer = new byte[receiveLength]; - - try - { - result = socket.Handle.Receive(receivedBuffer, socketFlags); - errno = SetResultErrno(socket.Handle, result); - - context.Memory.WriteBytes(receivePosition, receivedBuffer); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, result, errno); - } - - [Command(9)] - // RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer message, buffer) - public ResultCode RecvFrom(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); - - (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); - (long sockAddrOutPosition, long sockAddrOutSize) = context.Request.GetBufferType0x22(1); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0 - && (socketFlags & SocketFlags.Peek) == 0) - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}"); - - return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - } - - byte[] receivedBuffer = new byte[receiveLength]; - EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0); - - try - { - result = socket.Handle.ReceiveFrom(receivedBuffer, receivedBuffer.Length, socketFlags, ref endPoint); - errno = SetResultErrno(socket.Handle, result); - - context.Memory.WriteBytes(receivePosition, receivedBuffer); - WriteSockAddr(context, sockAddrOutPosition, (IPEndPoint)endPoint); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, result, errno); - } - - [Command(10)] - // Send(u32 socket, u32 flags, buffer) -> (i32 ret, u32 bsd_errno) - public ResultCode Send(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); - - (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand - && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute) - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}"); - - return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - } - - byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); - - try - { - result = socket.Handle.Send(sendBuffer, socketFlags); - errno = SetResultErrno(socket.Handle, result); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - - } - - return WriteBsdResult(context, result, errno); - } - - [Command(11)] - // SendTo(u32 socket, u32 flags, buffer, buffer) -> (i32 ret, u32 bsd_errno) - public ResultCode SendTo(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); - - (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); - (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(1); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand - && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute) - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}"); - - return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); - } - - byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); - EndPoint endPoint = ParseSockAddr(context, bufferPosition, bufferSize); - - try - { - result = socket.Handle.SendTo(sendBuffer, sendBuffer.Length, socketFlags, endPoint); - errno = SetResultErrno(socket.Handle, result); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - - } - - return WriteBsdResult(context, result, errno); - } - - [Command(12)] - // Accept(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) - public ResultCode Accept(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - Socket newSocket = null; - - try - { - newSocket = socket.Handle.Accept(); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - - if (newSocket == null && errno == LinuxError.SUCCESS) - { - errno = LinuxError.EWOULDBLOCK; - } - else if (errno == LinuxError.SUCCESS) - { - BsdSocket newBsdSocket = new BsdSocket - { - Family = (int)newSocket.AddressFamily, - Type = (int)newSocket.SocketType, - Protocol = (int)newSocket.ProtocolType, - Handle = newSocket - }; - - _sockets.Add(newBsdSocket); - - WriteSockAddr(context, bufferPos, newBsdSocket, true); - - WriteBsdResult(context, _sockets.Count - 1, errno); - - context.ResponseData.Write(0x10); - - return ResultCode.Success; - } - } - - return WriteBsdResult(context, -1, errno); - } - - [Command(13)] - // Bind(u32 socket, buffer addr) -> (i32 ret, u32 bsd_errno) - public ResultCode Bind(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - try - { - IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize); - - socket.Handle.Bind(endPoint); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(14)] - // Connect(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) - public ResultCode Connect(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - try - { - IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize); - - socket.Handle.Connect(endPoint); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(15)] - // GetPeerName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) - public ResultCode GetPeerName(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - WriteSockAddr(context, bufferPos, socket, true); - WriteBsdResult(context, 0, errno); - context.ResponseData.Write(0x10); - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(16)] - // GetSockName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) - public ResultCode GetSockName(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - WriteSockAddr(context, bufferPos, socket, false); - WriteBsdResult(context, 0, errno); - context.ResponseData.Write(0x10); - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(17)] - // GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer) - public ResultCode GetSockOpt(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - int level = context.RequestData.ReadInt32(); - int optionName = context.RequestData.ReadInt32(); - - (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.ENOPROTOOPT; - - if (level == 0xFFFF) - { - errno = HandleGetSocketOption(context, socket, (SocketOptionName)optionName, bufferPosition, bufferSize); - } - else - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported GetSockOpt Level: {(SocketOptionLevel)level}"); - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(18)] - // Listen(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno) - public ResultCode Listen(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - int backlog = context.RequestData.ReadInt32(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - try - { - socket.Handle.Listen(backlog); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(19)] - // Ioctl(u32 fd, u32 request, u32 bufcount, buffer, buffer, buffer, buffer) -> (i32 ret, u32 bsd_errno, buffer, buffer, buffer, buffer) - public ResultCode Ioctl(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - BsdIoctl cmd = (BsdIoctl)context.RequestData.ReadInt32(); - int bufferCount = context.RequestData.ReadInt32(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - switch (cmd) - { - case BsdIoctl.AtMark: - errno = LinuxError.SUCCESS; - - (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22(); - - // FIXME: OOB not implemented. - context.Memory.WriteInt32(bufferPosition, 0); - break; - - default: - errno = LinuxError.EOPNOTSUPP; - - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Ioctl Cmd: {cmd}"); - break; - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(20)] - // Fcntl(u32 socket, u32 cmd, u32 arg) -> (i32 ret, u32 bsd_errno) - public ResultCode Fcntl(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - int cmd = context.RequestData.ReadInt32(); - int arg = context.RequestData.ReadInt32(); - - int result = 0; - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.SUCCESS; - - if (cmd == 0x3) - { - result = !socket.Handle.Blocking ? 0x800 : 0; - } - else if (cmd == 0x4 && arg == 0x800) - { - socket.Handle.Blocking = false; - result = 0; - } - else - { - errno = LinuxError.EOPNOTSUPP; - } - } - - return WriteBsdResult(context, result, errno); - } - - private LinuxError HandleGetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize) - { - try - { - byte[] optionValue = new byte[optionValueSize]; - - switch (optionName) - { - case SocketOptionName.Broadcast: - case SocketOptionName.DontLinger: - case SocketOptionName.Debug: - case SocketOptionName.Error: - case SocketOptionName.KeepAlive: - case SocketOptionName.OutOfBandInline: - case SocketOptionName.ReceiveBuffer: - case SocketOptionName.ReceiveTimeout: - case SocketOptionName.SendBuffer: - case SocketOptionName.SendTimeout: - case SocketOptionName.Type: - case SocketOptionName.Linger: - socket.Handle.GetSocketOption(SocketOptionLevel.Socket, optionName, optionValue); - context.Memory.WriteBytes(optionValuePosition, optionValue); - - return LinuxError.SUCCESS; - - case (SocketOptionName)0x200: - socket.Handle.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue); - context.Memory.WriteBytes(optionValuePosition, optionValue); - - return LinuxError.SUCCESS; - - default: - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}"); - - return LinuxError.EOPNOTSUPP; - } - } - catch (SocketException exception) - { - return ConvertError((WsaError)exception.ErrorCode); - } - } - - private LinuxError HandleSetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize) - { - try - { - switch (optionName) - { - case SocketOptionName.Broadcast: - case SocketOptionName.DontLinger: - case SocketOptionName.Debug: - case SocketOptionName.Error: - case SocketOptionName.KeepAlive: - case SocketOptionName.OutOfBandInline: - case SocketOptionName.ReceiveBuffer: - case SocketOptionName.ReceiveTimeout: - case SocketOptionName.SendBuffer: - case SocketOptionName.SendTimeout: - case SocketOptionName.Type: - case SocketOptionName.ReuseAddress: - socket.Handle.SetSocketOption(SocketOptionLevel.Socket, optionName, context.Memory.ReadInt32(optionValuePosition)); - - return LinuxError.SUCCESS; - - case (SocketOptionName)0x200: - socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, context.Memory.ReadInt32(optionValuePosition)); - - return LinuxError.SUCCESS; - - case SocketOptionName.Linger: - socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, - new LingerOption(context.Memory.ReadInt32(optionValuePosition) != 0, context.Memory.ReadInt32(optionValuePosition + 4))); - - return LinuxError.SUCCESS; - - default: - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}"); - - return LinuxError.EOPNOTSUPP; - } - } - catch (SocketException exception) - { - return ConvertError((WsaError)exception.ErrorCode); - } - } - - [Command(21)] - // SetSockOpt(u32 socket, u32 level, u32 option_name, buffer option_value) -> (i32 ret, u32 bsd_errno) - public ResultCode SetSockOpt(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - int level = context.RequestData.ReadInt32(); - int optionName = context.RequestData.ReadInt32(); - - (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.ENOPROTOOPT; - - if (level == 0xFFFF) - { - errno = HandleSetSocketOption(context, socket, (SocketOptionName)optionName, bufferPos, bufferSize); - } - else - { - Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt Level: {(SocketOptionLevel)level}"); - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(22)] - // Shutdown(u32 socket, u32 how) -> (i32 ret, u32 bsd_errno) - public ResultCode Shutdown(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - int how = context.RequestData.ReadInt32(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - errno = LinuxError.EINVAL; - - if (how >= 0 && how <= 2) - { - errno = LinuxError.SUCCESS; - - try - { - socket.Handle.Shutdown((SocketShutdown)how); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(23)] - // ShutdownAllSockets(u32 how) -> (i32 ret, u32 bsd_errno) - public ResultCode ShutdownAllSockets(ServiceCtx context) - { - int how = context.RequestData.ReadInt32(); - - LinuxError errno = LinuxError.EINVAL; - - if (how >= 0 && how <= 2) - { - errno = LinuxError.SUCCESS; - - foreach (BsdSocket socket in _sockets) - { - if (socket != null) - { - try - { - socket.Handle.Shutdown((SocketShutdown)how); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - break; - } - } - } - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(24)] - // Write(u32 socket, buffer message) -> (i32 ret, u32 bsd_errno) - public ResultCode Write(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); - - try - { - result = socket.Handle.Send(sendBuffer); - errno = SetResultErrno(socket.Handle, result); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, result, errno); - } - - [Command(25)] - // Read(u32 socket) -> (i32 ret, u32 bsd_errno, buffer message) - public ResultCode Read(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - int result = -1; - - if (socket != null) - { - byte[] receivedBuffer = new byte[receiveLength]; - - try - { - result = socket.Handle.Receive(receivedBuffer); - errno = SetResultErrno(socket.Handle, result); - } - catch (SocketException exception) - { - errno = ConvertError((WsaError)exception.ErrorCode); - } - } - - return WriteBsdResult(context, result, errno); - } - - [Command(26)] - // Close(u32 socket) -> (i32 ret, u32 bsd_errno) - public ResultCode Close(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - - LinuxError errno = LinuxError.EBADF; - BsdSocket socket = RetrieveSocket(socketFd); - - if (socket != null) - { - socket.Handle.Close(); - - _sockets[socketFd] = null; - - errno = LinuxError.SUCCESS; - } - - return WriteBsdResult(context, 0, errno); - } - - [Command(27)] - // DuplicateSocket(u32 socket, u64 reserved) -> (i32 ret, u32 bsd_errno) - public ResultCode DuplicateSocket(ServiceCtx context) - { - int socketFd = context.RequestData.ReadInt32(); - ulong reserved = context.RequestData.ReadUInt64(); - - LinuxError errno = LinuxError.ENOENT; - int newSockFd = -1; - - if (_isPrivileged) - { - errno = LinuxError.EBADF; - - BsdSocket oldSocket = RetrieveSocket(socketFd); - - if (oldSocket != null) - { - _sockets.Add(oldSocket); - newSockFd = _sockets.Count - 1; - } - } - - return WriteBsdResult(context, newSockFd, errno); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bsd/PollEvent.cs b/Ryujinx.HLE/HOS/Services/Bsd/PollEvent.cs deleted file mode 100644 index b1e6ccc7..00000000 --- a/Ryujinx.HLE/HOS/Services/Bsd/PollEvent.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Bsd -{ - class PollEvent - { - public enum EventTypeMask - { - Input = 1, - UrgentInput = 2, - Output = 4, - Error = 8, - Disconnected = 0x10, - Invalid = 0x20 - } - - public int SocketFd { get; private set; } - public BsdSocket Socket { get; private set; } - public EventTypeMask InputEvents { get; private set; } - public EventTypeMask OutputEvents { get; private set; } - - public PollEvent(int socketFd, BsdSocket socket, EventTypeMask inputEvents, EventTypeMask outputEvents) - { - SocketFd = socketFd; - Socket = socket; - InputEvents = inputEvents; - OutputEvents = outputEvents; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Btm/BtmUser/IBtmUserCore.cs b/Ryujinx.HLE/HOS/Services/Btm/BtmUser/IBtmUserCore.cs new file mode 100644 index 00000000..0ab9a3ef --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Btm/BtmUser/IBtmUserCore.cs @@ -0,0 +1,128 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Btm.BtmUser +{ + class IBtmUserCore : IpcService + { + public KEvent _bleScanEvent; + public int _bleScanEventHandle; + + public KEvent _bleConnectionEvent; + public int _bleConnectionEventHandle; + + public KEvent _bleServiceDiscoveryEvent; + public int _bleServiceDiscoveryEventHandle; + + public KEvent _bleMtuConfigEvent; + public int _bleMtuConfigEventHandle; + + public IBtmUserCore() { } + + [Command(0)] // 5.0.0+ + // AcquireBleScanEvent() -> (byte<1>, handle) + public ResultCode AcquireBleScanEvent(ServiceCtx context) + { + KernelResult result = KernelResult.Success; + + if (_bleScanEventHandle == 0) + { + _bleScanEvent = new KEvent(context.Device.System); + + result = context.Process.HandleTable.GenerateHandle(_bleScanEvent.ReadableEvent, out _bleScanEventHandle); + + if (result != KernelResult.Success) + { + // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. + Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleScanEventHandle); + + context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); + + return ResultCode.Success; + } + + [Command(17)] // 5.0.0+ + // AcquireBleConnectionEvent() -> (byte<1>, handle) + public ResultCode AcquireBleConnectionEvent(ServiceCtx context) + { + KernelResult result = KernelResult.Success; + + if (_bleConnectionEventHandle == 0) + { + _bleConnectionEvent = new KEvent(context.Device.System); + + result = context.Process.HandleTable.GenerateHandle(_bleConnectionEvent.ReadableEvent, out _bleConnectionEventHandle); + + if (result != KernelResult.Success) + { + // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. + Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleConnectionEventHandle); + + context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); + + return ResultCode.Success; + } + + [Command(26)] // 5.0.0+ + // AcquireBleServiceDiscoveryEvent() -> (byte<1>, handle) + public ResultCode AcquireBleServiceDiscoveryEvent(ServiceCtx context) + { + KernelResult result = KernelResult.Success; + + if (_bleServiceDiscoveryEventHandle == 0) + { + _bleServiceDiscoveryEvent = new KEvent(context.Device.System); + + result = context.Process.HandleTable.GenerateHandle(_bleServiceDiscoveryEvent.ReadableEvent, out _bleServiceDiscoveryEventHandle); + + if (result != KernelResult.Success) + { + // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. + Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleServiceDiscoveryEventHandle); + + context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); + + return ResultCode.Success; + } + + [Command(33)] // 5.0.0+ + // AcquireBleMtuConfigEvent() -> (byte<1>, handle) + public ResultCode AcquireBleMtuConfigEvent(ServiceCtx context) + { + KernelResult result = KernelResult.Success; + + if (_bleMtuConfigEventHandle == 0) + { + _bleMtuConfigEvent = new KEvent(context.Device.System); + + result = context.Process.HandleTable.GenerateHandle(_bleMtuConfigEvent.ReadableEvent, out _bleMtuConfigEventHandle); + + if (result != KernelResult.Success) + { + // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. + Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleMtuConfigEventHandle); + + context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Btm/IBtmDebug.cs b/Ryujinx.HLE/HOS/Services/Btm/IBtmDebug.cs new file mode 100644 index 00000000..a55b7da8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Btm/IBtmDebug.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Btm +{ + [Service("btm:dbg")] + class IBtmDebug : IpcService + { + public IBtmDebug(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Btm/IBtmSystem.cs b/Ryujinx.HLE/HOS/Services/Btm/IBtmSystem.cs new file mode 100644 index 00000000..9120762c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Btm/IBtmSystem.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Btm +{ + [Service("btm:sys")] + class IBtmSystem : IpcService + { + public IBtmSystem(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Btm/IBtmUser.cs b/Ryujinx.HLE/HOS/Services/Btm/IBtmUser.cs index 133ef0cc..68694187 100644 --- a/Ryujinx.HLE/HOS/Services/Btm/IBtmUser.cs +++ b/Ryujinx.HLE/HOS/Services/Btm/IBtmUser.cs @@ -1,6 +1,8 @@ -namespace Ryujinx.HLE.HOS.Services.Btm +using Ryujinx.HLE.HOS.Services.Btm.BtmUser; + +namespace Ryujinx.HLE.HOS.Services.Btm { - [Service("btm:u")] + [Service("btm:u")] // 5.0.0+ class IBtmUser : IpcService { public IBtmUser(ServiceCtx context) { } diff --git a/Ryujinx.HLE/HOS/Services/Btm/IBtmUserCore.cs b/Ryujinx.HLE/HOS/Services/Btm/IBtmUserCore.cs deleted file mode 100644 index 14b7b5f3..00000000 --- a/Ryujinx.HLE/HOS/Services/Btm/IBtmUserCore.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Btm -{ - class IBtmUserCore : IpcService - { - public KEvent _bleScanEvent; - public int _bleScanEventHandle; - - public KEvent _bleConnectionEvent; - public int _bleConnectionEventHandle; - - public KEvent _bleServiceDiscoveryEvent; - public int _bleServiceDiscoveryEventHandle; - - public KEvent _bleMtuConfigEvent; - public int _bleMtuConfigEventHandle; - - public IBtmUserCore() { } - - [Command(0)] // 5.0.0+ - // AcquireBleScanEvent() -> (byte<1>, handle) - public ResultCode AcquireBleScanEvent(ServiceCtx context) - { - KernelResult result = KernelResult.Success; - - if (_bleScanEventHandle == 0) - { - _bleScanEvent = new KEvent(context.Device.System); - - result = context.Process.HandleTable.GenerateHandle(_bleScanEvent.ReadableEvent, out _bleScanEventHandle); - - if (result != KernelResult.Success) - { - // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. - Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleScanEventHandle); - - context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); - - return ResultCode.Success; - } - - [Command(17)] // 5.0.0+ - // AcquireBleConnectionEvent() -> (byte<1>, handle) - public ResultCode AcquireBleConnectionEvent(ServiceCtx context) - { - KernelResult result = KernelResult.Success; - - if (_bleConnectionEventHandle == 0) - { - _bleConnectionEvent = new KEvent(context.Device.System); - - result = context.Process.HandleTable.GenerateHandle(_bleConnectionEvent.ReadableEvent, out _bleConnectionEventHandle); - - if (result != KernelResult.Success) - { - // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. - Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleConnectionEventHandle); - - context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); - - return ResultCode.Success; - } - - [Command(26)] // 5.0.0+ - // AcquireBleServiceDiscoveryEvent() -> (byte<1>, handle) - public ResultCode AcquireBleServiceDiscoveryEvent(ServiceCtx context) - { - KernelResult result = KernelResult.Success; - - if (_bleServiceDiscoveryEventHandle == 0) - { - _bleServiceDiscoveryEvent = new KEvent(context.Device.System); - - result = context.Process.HandleTable.GenerateHandle(_bleServiceDiscoveryEvent.ReadableEvent, out _bleServiceDiscoveryEventHandle); - - if (result != KernelResult.Success) - { - // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. - Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleServiceDiscoveryEventHandle); - - context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); - - return ResultCode.Success; - } - - [Command(33)] // 5.0.0+ - // AcquireBleMtuConfigEvent() -> (byte<1>, handle) - public ResultCode AcquireBleMtuConfigEvent(ServiceCtx context) - { - KernelResult result = KernelResult.Success; - - if (_bleMtuConfigEventHandle == 0) - { - _bleMtuConfigEvent = new KEvent(context.Device.System); - - result = context.Process.HandleTable.GenerateHandle(_bleMtuConfigEvent.ReadableEvent, out _bleMtuConfigEventHandle); - - if (result != KernelResult.Success) - { - // NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not. - Logger.PrintError(LogClass.ServiceBsd, "Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleMtuConfigEventHandle); - - context.ResponseData.Write(result == KernelResult.Success ? 1 : 0); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IAlbumApplicationService.cs b/Ryujinx.HLE/HOS/Services/Caps/IAlbumApplicationService.cs new file mode 100644 index 00000000..199d6aa3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IAlbumApplicationService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Caps +{ + [Service("caps:u")] + class IAlbumApplicationService : IpcService + { + public IAlbumApplicationService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IAlbumControlService.cs b/Ryujinx.HLE/HOS/Services/Caps/IAlbumControlService.cs new file mode 100644 index 00000000..de880153 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IAlbumControlService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Caps +{ + [Service("caps:c")] + class IAlbumControlService : IpcService + { + public IAlbumControlService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs new file mode 100644 index 00000000..209bfd3d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Caps +{ + [Service("caps:su")] // 6.0.0+ + class IScreenShotApplicationService : IpcService + { + public IScreenShotApplicationService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IScreenShotControlService.cs b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotControlService.cs new file mode 100644 index 00000000..337fa9ee --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotControlService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Caps +{ + [Service("caps:sc")] + class IScreenShotControlService : IpcService + { + public IScreenShotControlService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs b/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs index 6c34f2a0..03703e05 100644 --- a/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs +++ b/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs @@ -1,6 +1,6 @@ namespace Ryujinx.HLE.HOS.Services.Caps { - [Service("caps:ss")] + [Service("caps:ss")] // 2.0.0+ class IScreenshotService : IpcService { public IScreenshotService(ServiceCtx context) { } diff --git a/Ryujinx.HLE/HOS/Services/Cec/ICecManager.cs b/Ryujinx.HLE/HOS/Services/Cec/ICecManager.cs new file mode 100644 index 00000000..71c26786 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Cec/ICecManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Cec +{ + [Service("cec-mgr")] + class ICecManager : IpcService + { + public ICecManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Erpt/IContext.cs b/Ryujinx.HLE/HOS/Services/Erpt/IContext.cs new file mode 100644 index 00000000..9a689172 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Erpt/IContext.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Erpt +{ + [Service("erpt:c")] + class IContext : IpcService + { + public IContext(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Erpt/ISession.cs b/Ryujinx.HLE/HOS/Services/Erpt/ISession.cs new file mode 100644 index 00000000..6397afae --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Erpt/ISession.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Erpt +{ + [Service("erpt:r")] + class ISession : IpcService + { + public ISession(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Es/IETicketService.cs b/Ryujinx.HLE/HOS/Services/Es/IETicketService.cs index f8ecb85c..34be7bdd 100644 --- a/Ryujinx.HLE/HOS/Services/Es/IETicketService.cs +++ b/Ryujinx.HLE/HOS/Services/Es/IETicketService.cs @@ -1,8 +1,8 @@ namespace Ryujinx.HLE.HOS.Services.Es { [Service("es")] - class IeTicketService : IpcService + class IETicketService : IpcService { - public IeTicketService(ServiceCtx context) { } + public IETicketService(ServiceCtx context) { } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Eupld/IControl.cs b/Ryujinx.HLE/HOS/Services/Eupld/IControl.cs new file mode 100644 index 00000000..dd8705e6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Eupld/IControl.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Eupld +{ + [Service("eupld:c")] + class IControl : IpcService + { + public IControl(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Eupld/IRequest.cs b/Ryujinx.HLE/HOS/Services/Eupld/IRequest.cs new file mode 100644 index 00000000..85097878 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Eupld/IRequest.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Eupld +{ + [Service("eupld:r")] + class IRequest : IpcService + { + public IRequest(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fatal/IPrivateService.cs b/Ryujinx.HLE/HOS/Services/Fatal/IPrivateService.cs new file mode 100644 index 00000000..eb2c9553 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fatal/IPrivateService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Fatal +{ + [Service("fatal:p")] + class IPrivateService : IpcService + { + public IPrivateService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fatal/IService.cs b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs new file mode 100644 index 00000000..692d2b0b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Fatal +{ + [Service("fatal:u")] + class IService : IpcService + { + public IService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/FriendServicePermissionLevel.cs b/Ryujinx.HLE/HOS/Services/Friend/FriendServicePermissionLevel.cs deleted file mode 100644 index a2a4031a..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/FriendServicePermissionLevel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - [Flags] - enum FriendServicePermissionLevel - { - UserMask = 1, - OverlayMask = 2, - ManagerMask = 4, - SystemMask = 8, - - Admin = -1, - User = UserMask, - Overlay = UserMask | OverlayMask, - Manager = UserMask | OverlayMask | ManagerMask, - System = UserMask | SystemMask - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs b/Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs deleted file mode 100644 index 0156e0b7..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend -{ - class IDaemonSuspendSessionService : IpcService - { - private FriendServicePermissionLevel PermissionLevel; - - public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel) - { - PermissionLevel = permissionLevel; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs deleted file mode 100644 index ed3bc284..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs +++ /dev/null @@ -1,169 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Utilities; -using System.IO; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - class IFriendService : IpcService - { - private FriendServicePermissionLevel _permissionLevel; - - public IFriendService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [Command(10100)] - // nn::friends::GetFriendListIds(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UInt128 uuid = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.PrintStub(LogClass.ServiceFriend, new - { - UserId = uuid.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [Command(10101)] - // nn::friends::GetFriendList(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendList(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UInt128 uuid = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.PrintStub(LogClass.ServiceFriend, new { - UserId = uuid.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [Command(10600)] - // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid) - public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) - { - UInt128 uuid = context.RequestData.ReadStruct(); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile)) - { - profile.OnlinePlayState = AccountState.Open; - } - - Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState }); - - return ResultCode.Success; - } - - [Command(10601)] - // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid) - public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context) - { - UInt128 uuid = context.RequestData.ReadStruct(); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile)) - { - profile.OnlinePlayState = AccountState.Closed; - } - - Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState }); - - return ResultCode.Success; - } - - [Command(10610)] - // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer) - public ResultCode UpdateUserPresence(ServiceCtx context) - { - UInt128 uuid = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - long position = context.Request.PtrBuff[0].Position; - long size = context.Request.PtrBuff[0].Size; - - byte[] bufferContent = context.Memory.ReadBytes(position, size); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - int elementCount = bufferContent.Length / Marshal.SizeOf(); - - using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent))) - { - UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray(elementCount); - - Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray }); - } - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs b/Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs deleted file mode 100644 index 5a5238f5..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Ryujinx.HLE.Utilities; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - enum PresenceStatusFilter : uint - { - None, - Online, - OnlinePlay, - OnlineOrOnlinePlay - } - - enum PresenceStatus : uint - { - Offline, - Online, - OnlinePlay, - } - - [StructLayout(LayoutKind.Sequential)] - struct FriendFilter - { - public PresenceStatusFilter PresenceStatus; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavoriteOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPresenceOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPlayedOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsArbitraryAppPlayedOnly; - - public long PresenceGroupId; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)] - struct UserPresence - { - public UInt128 UserId; - public long LastTimeOnlineTimestamp; - public PresenceStatus Status; - - [MarshalAs(UnmanagedType.I1)] - public bool SamePresenceGroupApplication; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] - char[] Unknown; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)] - public char[] AppKeyValueStorage; - - public override string ToString() - { - return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}"; - } - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)] - struct Friend - { - public UInt128 UserId; - public long NetworkUserId; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)] - public string Nickname; - - public UserPresence presence; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavourite; - - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x6)] - char[] Unknown; - - [MarshalAs(UnmanagedType.I1)] - public bool IsValid; - } - - enum NotificationEventType : uint - { - Invalid = 0x0, - FriendListUpdate = 0x1, - NewFriendRequest = 0x65, - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)] - struct NotificationInfo - { - public NotificationEventType Type; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)] - char[] Padding; - - public long NetworkUserIdPlaceholder; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs b/Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs deleted file mode 100644 index 7cff84bd..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs +++ /dev/null @@ -1,174 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.Utilities; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - class INotificationService : IpcService, IDisposable - { - private readonly UInt128 _userId; - private readonly FriendServicePermissionLevel _permissionLevel; - - private readonly object _lock = new object(); - - private KEvent _notificationEvent; - private int _notificationEventHandle = 0; - - private LinkedList _notifications; - - private bool _hasNewFriendRequest; - private bool _hasFriendListUpdate; - - public INotificationService(ServiceCtx context, UInt128 userId, FriendServicePermissionLevel permissionLevel) - { - _userId = userId; - _permissionLevel = permissionLevel; - _notifications = new LinkedList(); - _notificationEvent = new KEvent(context.Device.System); - - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - NotificationEventHandler.Instance.RegisterNotificationService(this); - } - - [Command(0)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle - public ResultCode GetEvent(ServiceCtx context) - { - if (_notificationEventHandle == 0) - { - if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle); - - return ResultCode.Success; - } - - [Command(1)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::Clear() - public ResultCode Clear(ServiceCtx context) - { - lock (_lock) - { - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - _notifications.Clear(); - } - - return ResultCode.Success; - } - - [Command(2)] // 2.0.0+ - // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo - public ResultCode Pop(ServiceCtx context) - { - lock (_lock) - { - if (_notifications.Count >= 1) - { - NotificationInfo notificationInfo = _notifications.First.Value; - _notifications.RemoveFirst(); - - if (notificationInfo.Type == NotificationEventType.FriendListUpdate) - { - _hasFriendListUpdate = false; - } - else if (notificationInfo.Type == NotificationEventType.NewFriendRequest) - { - _hasNewFriendRequest = false; - } - - context.ResponseData.WriteStruct(notificationInfo); - - return ResultCode.Success; - } - } - - return ResultCode.NotificationQueueEmpty; - } - - public void SignalFriendListUpdate(UInt128 targetId) - { - lock (_lock) - { - if (_userId == targetId) - { - if (!_hasFriendListUpdate) - { - NotificationInfo friendListNotification = new NotificationInfo(); - - if (_notifications.Count != 0) - { - friendListNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - friendListNotification.Type = NotificationEventType.FriendListUpdate; - _hasFriendListUpdate = true; - - if (_hasNewFriendRequest) - { - NotificationInfo newFriendRequestNotification = new NotificationInfo(); - - if (_notifications.Count != 0) - { - newFriendRequestNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; - _notifications.AddFirst(newFriendRequestNotification); - } - - // We defer this to make sure we are on top of the queue. - _notifications.AddFirst(friendListNotification); - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - public void SignalNewFriendRequest(UInt128 targetId) - { - lock (_lock) - { - if ((_permissionLevel & FriendServicePermissionLevel.OverlayMask) != 0 && _userId == targetId) - { - if (!_hasNewFriendRequest) - { - if (_notifications.Count == 100) - { - SignalFriendListUpdate(targetId); - } - - NotificationInfo newFriendRequestNotification = new NotificationInfo - { - Type = NotificationEventType.NewFriendRequest - }; - - _notifications.AddLast(newFriendRequestNotification); - _hasNewFriendRequest = true; - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - public void Dispose() - { - NotificationEventHandler.Instance.UnregisterNotificationService(this); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs index c907a2ed..cec3c422 100644 --- a/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator; using Ryujinx.HLE.Utilities; namespace Ryujinx.HLE.HOS.Services.Friend diff --git a/Ryujinx.HLE/HOS/Services/Friend/NotificationEventHandler.cs b/Ryujinx.HLE/HOS/Services/Friend/NotificationEventHandler.cs deleted file mode 100644 index 8582a074..00000000 --- a/Ryujinx.HLE/HOS/Services/Friend/NotificationEventHandler.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Ryujinx.HLE.Utilities; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - public sealed class NotificationEventHandler - { - private static NotificationEventHandler instance; - private static object instanceLock = new object(); - - private INotificationService[] _registry; - - public static NotificationEventHandler Instance - { - get - { - lock (instanceLock) - { - if (instance == null) - { - instance = new NotificationEventHandler(); - } - - return instance; - } - } - } - - NotificationEventHandler() - { - _registry = new INotificationService[0x20]; - } - - internal void RegisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't space anymore in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == null) - { - _registry[i] = service; - break; - } - } - } - - internal void UnregisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't the entry in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == service) - { - _registry[i] = null; - break; - } - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalFriendListUpdate(UInt128 targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] != null) - { - _registry[i].SignalFriendListUpdate(targetId); - } - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalNewFriendRequest(UInt128 targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] != null) - { - _registry[i].SignalNewFriendRequest(targetId); - } - } - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs new file mode 100644 index 00000000..4947a5ce --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs @@ -0,0 +1,29 @@ +using Ryujinx.HLE.Utilities; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)] + struct Friend + { + public UInt128 UserId; + public long NetworkUserId; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)] + public string Nickname; + + public UserPresence presence; + + [MarshalAs(UnmanagedType.I1)] + public bool IsFavourite; + + [MarshalAs(UnmanagedType.I1)] + public bool IsNew; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x6)] + char[] Unknown; + + [MarshalAs(UnmanagedType.I1)] + public bool IsValid; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs new file mode 100644 index 00000000..261bf7bf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs @@ -0,0 +1,24 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +{ + [StructLayout(LayoutKind.Sequential)] + struct FriendFilter + { + public PresenceStatusFilter PresenceStatus; + + [MarshalAs(UnmanagedType.I1)] + public bool IsFavoriteOnly; + + [MarshalAs(UnmanagedType.I1)] + public bool IsSameAppPresenceOnly; + + [MarshalAs(UnmanagedType.I1)] + public bool IsSameAppPlayedOnly; + + [MarshalAs(UnmanagedType.I1)] + public bool IsArbitraryAppPlayedOnly; + + public long PresenceGroupId; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs new file mode 100644 index 00000000..df2e6525 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +{ + enum PresenceStatus : uint + { + Offline, + Online, + OnlinePlay + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs new file mode 100644 index 00000000..24da7fd3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +{ + enum PresenceStatusFilter : uint + { + None, + Online, + OnlinePlay, + OnlineOrOnlinePlay + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs new file mode 100644 index 00000000..5fe8bfd7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.Utilities; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)] + struct UserPresence + { + public UInt128 UserId; + public long LastTimeOnlineTimestamp; + public PresenceStatus Status; + + [MarshalAs(UnmanagedType.I1)] + public bool SamePresenceGroupApplication; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] + public char[] Unknown; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)] + public char[] AppKeyValueStorage; + + public override string ToString() + { + return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}"; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs new file mode 100644 index 00000000..42b34312 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +{ + class IDaemonSuspendSessionService : IpcService + { + private FriendServicePermissionLevel PermissionLevel; + + public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel) + { + PermissionLevel = permissionLevel; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs new file mode 100644 index 00000000..7492c5a7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs @@ -0,0 +1,170 @@ +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Account.Acc; +using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService; +using Ryujinx.HLE.Utilities; +using System.IO; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +{ + class IFriendService : IpcService + { + private FriendServicePermissionLevel _permissionLevel; + + public IFriendService(FriendServicePermissionLevel permissionLevel) + { + _permissionLevel = permissionLevel; + } + + [Command(10100)] + // nn::friends::GetFriendListIds(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) + // -> int outCount, array + public ResultCode GetFriendListIds(ServiceCtx context) + { + int offset = context.RequestData.ReadInt32(); + + // Padding + context.RequestData.ReadInt32(); + + UInt128 uuid = context.RequestData.ReadStruct(); + FriendFilter filter = context.RequestData.ReadStruct(); + + // Pid placeholder + context.RequestData.ReadInt64(); + + if (uuid.IsNull) + { + return ResultCode.InvalidArgument; + } + + // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. + context.ResponseData.Write(0); + + Logger.PrintStub(LogClass.ServiceFriend, new + { + UserId = uuid.ToString(), + offset, + filter.PresenceStatus, + filter.IsFavoriteOnly, + filter.IsSameAppPresenceOnly, + filter.IsSameAppPlayedOnly, + filter.IsArbitraryAppPlayedOnly, + filter.PresenceGroupId, + }); + + return ResultCode.Success; + } + + [Command(10101)] + // nn::friends::GetFriendList(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) + // -> int outCount, array + public ResultCode GetFriendList(ServiceCtx context) + { + int offset = context.RequestData.ReadInt32(); + + // Padding + context.RequestData.ReadInt32(); + + UInt128 uuid = context.RequestData.ReadStruct(); + FriendFilter filter = context.RequestData.ReadStruct(); + + // Pid placeholder + context.RequestData.ReadInt64(); + + if (uuid.IsNull) + { + return ResultCode.InvalidArgument; + } + + // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. + context.ResponseData.Write(0); + + Logger.PrintStub(LogClass.ServiceFriend, new { + UserId = uuid.ToString(), + offset, + filter.PresenceStatus, + filter.IsFavoriteOnly, + filter.IsSameAppPresenceOnly, + filter.IsSameAppPlayedOnly, + filter.IsArbitraryAppPlayedOnly, + filter.PresenceGroupId, + }); + + return ResultCode.Success; + } + + [Command(10600)] + // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid) + public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) + { + UInt128 uuid = context.RequestData.ReadStruct(); + + if (uuid.IsNull) + { + return ResultCode.InvalidArgument; + } + + if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile)) + { + profile.OnlinePlayState = AccountState.Open; + } + + Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState }); + + return ResultCode.Success; + } + + [Command(10601)] + // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid) + public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context) + { + UInt128 uuid = context.RequestData.ReadStruct(); + + if (uuid.IsNull) + { + return ResultCode.InvalidArgument; + } + + if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile)) + { + profile.OnlinePlayState = AccountState.Closed; + } + + Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState }); + + return ResultCode.Success; + } + + [Command(10610)] + // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer) + public ResultCode UpdateUserPresence(ServiceCtx context) + { + UInt128 uuid = context.RequestData.ReadStruct(); + + // Pid placeholder + context.RequestData.ReadInt64(); + + long position = context.Request.PtrBuff[0].Position; + long size = context.Request.PtrBuff[0].Size; + + byte[] bufferContent = context.Memory.ReadBytes(position, size); + + if (uuid.IsNull) + { + return ResultCode.InvalidArgument; + } + + int elementCount = bufferContent.Length / Marshal.SizeOf(); + + using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent))) + { + UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray(elementCount); + + Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray }); + } + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs new file mode 100644 index 00000000..1ff37442 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs @@ -0,0 +1,175 @@ +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService; +using Ryujinx.HLE.Utilities; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +{ + class INotificationService : IpcService, IDisposable + { + private readonly UInt128 _userId; + private readonly FriendServicePermissionLevel _permissionLevel; + + private readonly object _lock = new object(); + + private KEvent _notificationEvent; + private int _notificationEventHandle = 0; + + private LinkedList _notifications; + + private bool _hasNewFriendRequest; + private bool _hasFriendListUpdate; + + public INotificationService(ServiceCtx context, UInt128 userId, FriendServicePermissionLevel permissionLevel) + { + _userId = userId; + _permissionLevel = permissionLevel; + _notifications = new LinkedList(); + _notificationEvent = new KEvent(context.Device.System); + + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + NotificationEventHandler.Instance.RegisterNotificationService(this); + } + + [Command(0)] //2.0.0+ + // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle + public ResultCode GetEvent(ServiceCtx context) + { + if (_notificationEventHandle == 0) + { + if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle); + + return ResultCode.Success; + } + + [Command(1)] //2.0.0+ + // nn::friends::detail::ipc::INotificationService::Clear() + public ResultCode Clear(ServiceCtx context) + { + lock (_lock) + { + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + _notifications.Clear(); + } + + return ResultCode.Success; + } + + [Command(2)] // 2.0.0+ + // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo + public ResultCode Pop(ServiceCtx context) + { + lock (_lock) + { + if (_notifications.Count >= 1) + { + NotificationInfo notificationInfo = _notifications.First.Value; + _notifications.RemoveFirst(); + + if (notificationInfo.Type == NotificationEventType.FriendListUpdate) + { + _hasFriendListUpdate = false; + } + else if (notificationInfo.Type == NotificationEventType.NewFriendRequest) + { + _hasNewFriendRequest = false; + } + + context.ResponseData.WriteStruct(notificationInfo); + + return ResultCode.Success; + } + } + + return ResultCode.NotificationQueueEmpty; + } + + public void SignalFriendListUpdate(UInt128 targetId) + { + lock (_lock) + { + if (_userId == targetId) + { + if (!_hasFriendListUpdate) + { + NotificationInfo friendListNotification = new NotificationInfo(); + + if (_notifications.Count != 0) + { + friendListNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + friendListNotification.Type = NotificationEventType.FriendListUpdate; + _hasFriendListUpdate = true; + + if (_hasNewFriendRequest) + { + NotificationInfo newFriendRequestNotification = new NotificationInfo(); + + if (_notifications.Count != 0) + { + newFriendRequestNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; + _notifications.AddFirst(newFriendRequestNotification); + } + + // We defer this to make sure we are on top of the queue. + _notifications.AddFirst(friendListNotification); + } + + _notificationEvent.ReadableEvent.Signal(); + } + } + } + + public void SignalNewFriendRequest(UInt128 targetId) + { + lock (_lock) + { + if ((_permissionLevel & FriendServicePermissionLevel.OverlayMask) != 0 && _userId == targetId) + { + if (!_hasNewFriendRequest) + { + if (_notifications.Count == 100) + { + SignalFriendListUpdate(targetId); + } + + NotificationInfo newFriendRequestNotification = new NotificationInfo + { + Type = NotificationEventType.NewFriendRequest + }; + + _notifications.AddLast(newFriendRequestNotification); + _hasNewFriendRequest = true; + } + + _notificationEvent.ReadableEvent.Signal(); + } + } + } + + public void Dispose() + { + NotificationEventHandler.Instance.UnregisterNotificationService(this); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs new file mode 100644 index 00000000..19b15416 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs @@ -0,0 +1,83 @@ +using Ryujinx.HLE.Utilities; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService +{ + public sealed class NotificationEventHandler + { + private static NotificationEventHandler instance; + private static object instanceLock = new object(); + + private INotificationService[] _registry; + + public static NotificationEventHandler Instance + { + get + { + lock (instanceLock) + { + if (instance == null) + { + instance = new NotificationEventHandler(); + } + + return instance; + } + } + } + + NotificationEventHandler() + { + _registry = new INotificationService[0x20]; + } + + internal void RegisterNotificationService(INotificationService service) + { + // NOTE: in case there isn't space anymore in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == null) + { + _registry[i] = service; + break; + } + } + } + + internal void UnregisterNotificationService(INotificationService service) + { + // NOTE: in case there isn't the entry in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == service) + { + _registry[i] = null; + break; + } + } + } + + // TODO: Use this when we will have enough things to go online. + public void SignalFriendListUpdate(UInt128 targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] != null) + { + _registry[i].SignalFriendListUpdate(targetId); + } + } + } + + // TODO: Use this when we will have enough things to go online. + public void SignalNewFriendRequest(UInt128 targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] != null) + { + _registry[i].SignalNewFriendRequest(targetId); + } + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs new file mode 100644 index 00000000..5136ae8a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService +{ + enum NotificationEventType : uint + { + Invalid = 0x0, + FriendListUpdate = 0x1, + NewFriendRequest = 0x65 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs new file mode 100644 index 00000000..1bd6f011 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)] + struct NotificationInfo + { + public NotificationEventType Type; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)] + public char[] Padding; + + public long NetworkUserIdPlaceholder; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs new file mode 100644 index 00000000..9c811365 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs @@ -0,0 +1,19 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +{ + [Flags] + enum FriendServicePermissionLevel + { + UserMask = 1, + OverlayMask = 2, + ManagerMask = 4, + SystemMask = 8, + + Admin = -1, + User = UserMask, + Overlay = UserMask | OverlayMask, + Manager = UserMask | OverlayMask | ManagerMask, + System = UserMask | SystemMask + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs new file mode 100644 index 00000000..04b87b57 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs @@ -0,0 +1,144 @@ +using LibHac; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; +using Ryujinx.Common; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Utilities; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + static class FileSystemProxyHelper + { + public static ResultCode LoadSaveDataFileSystem(ServiceCtx context, bool readOnly, out IFileSystem loadedFileSystem) + { + loadedFileSystem = null; + + SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64(); + ulong titleId = context.RequestData.ReadUInt64(); + UInt128 userId = context.RequestData.ReadStruct(); + long saveId = context.RequestData.ReadInt64(); + SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte(); + SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, saveSpaceId, userId); + string savePath = context.Device.FileSystem.GetSavePath(context, saveInfo); + + try + { + LocalFileSystem fileSystem = new LocalFileSystem(savePath); + LibHac.Fs.IFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem); + + if (readOnly) + { + saveFileSystem = new ReadOnlyFileSystem(saveFileSystem); + } + + loadedFileSystem = new IFileSystem(saveFileSystem); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenNsp(ServiceCtx context, string pfsPath, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + try + { + LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); + PartitionFileSystem nsp = new PartitionFileSystem(storage); + + ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); + + openedFileSystem = new IFileSystem(nsp); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + try + { + Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); + + if (!nca.SectionExists(NcaSectionType.Data)) + { + return ResultCode.PartitionNotFound; + } + + LibHac.Fs.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); + + openedFileSystem = new IFileSystem(fileSystem); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent; + + while (string.IsNullOrWhiteSpace(archivePath.Extension)) + { + archivePath = archivePath.Parent; + } + + if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName)) + { + FileStream pfsFile = new FileStream( + archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), + FileMode.Open, + FileAccess.Read); + + try + { + PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); + + ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); + + string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); + + if (nsp.FileExists(filename)) + { + return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage(), out openedFileSystem); + } + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + } + + return ResultCode.PathDoesNotExist; + } + + public static void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet) + { + foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) + { + Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); + + if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) + { + keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs new file mode 100644 index 00000000..4fc8a687 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs @@ -0,0 +1,84 @@ +using LibHac; +using System.Collections.Generic; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class IDirectory : IpcService + { + private const int DirectoryEntrySize = 0x310; + + private IEnumerator _enumerator; + + private LibHac.Fs.IDirectory _baseDirectory; + + public IDirectory(LibHac.Fs.IDirectory directory) + { + _baseDirectory = directory; + _enumerator = directory.Read().GetEnumerator(); + } + + [Command(0)] + // Read() -> (u64 count, buffer entries) + public ResultCode Read(ServiceCtx context) + { + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferLen = context.Request.ReceiveBuff[0].Size; + + int maxReadCount = (int)(bufferLen / DirectoryEntrySize); + int readCount = 0; + + try + { + while (readCount < maxReadCount && _enumerator.MoveNext()) + { + long position = bufferPosition + readCount * DirectoryEntrySize; + + WriteDirectoryEntry(context, position, _enumerator.Current); + + readCount++; + } + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + context.ResponseData.Write((long)readCount); + + return ResultCode.Success; + } + + private void WriteDirectoryEntry(ServiceCtx context, long position, LibHac.Fs.DirectoryEntry entry) + { + for (int offset = 0; offset < 0x300; offset += 8) + { + context.Memory.WriteInt64(position + offset, 0); + } + + byte[] nameBuffer = Encoding.UTF8.GetBytes(entry.Name); + + context.Memory.WriteBytes(position, nameBuffer); + + context.Memory.WriteInt32(position + 0x300, (int)entry.Attributes); + context.Memory.WriteInt32(position + 0x304, (byte)entry.Type); + context.Memory.WriteInt64(position + 0x308, entry.Size); + } + + [Command(1)] + // GetEntryCount() -> u64 + public ResultCode GetEntryCount(ServiceCtx context) + { + try + { + context.ResponseData.Write((long)_baseDirectory.GetEntryCount()); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs new file mode 100644 index 00000000..df9209e6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs @@ -0,0 +1,136 @@ +using LibHac; +using LibHac.Fs; +using System; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class IFile : IpcService, IDisposable + { + private LibHac.Fs.IFile _baseFile; + + public IFile(LibHac.Fs.IFile baseFile) + { + _baseFile = baseFile; + } + + [Command(0)] + // Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer out_buf) + public ResultCode Read(ServiceCtx context) + { + long position = context.Request.ReceiveBuff[0].Position; + + ReadOption readOption = (ReadOption)context.RequestData.ReadInt32(); + context.RequestData.BaseStream.Position += 4; + + long offset = context.RequestData.ReadInt64(); + long size = context.RequestData.ReadInt64(); + + byte[] data = new byte[size]; + int readSize; + + try + { + readSize = _baseFile.Read(data, offset, readOption); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + context.Memory.WriteBytes(position, data); + + context.ResponseData.Write((long)readSize); + + return ResultCode.Success; + } + + [Command(1)] + // Write(u32 writeOption, u64 offset, u64 size, buffer) + public ResultCode Write(ServiceCtx context) + { + long position = context.Request.SendBuff[0].Position; + + WriteOption writeOption = (WriteOption)context.RequestData.ReadInt32(); + context.RequestData.BaseStream.Position += 4; + + long offset = context.RequestData.ReadInt64(); + long size = context.RequestData.ReadInt64(); + + byte[] data = context.Memory.ReadBytes(position, size); + + try + { + _baseFile.Write(data, offset, writeOption); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(2)] + // Flush() + public ResultCode Flush(ServiceCtx context) + { + try + { + _baseFile.Flush(); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(3)] + // SetSize(u64 size) + public ResultCode SetSize(ServiceCtx context) + { + try + { + long size = context.RequestData.ReadInt64(); + + _baseFile.SetSize(size); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(4)] + // GetSize() -> u64 fileSize + public ResultCode GetSize(ServiceCtx context) + { + try + { + context.ResponseData.Write(_baseFile.GetSize()); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _baseFile?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs new file mode 100644 index 00000000..7a7fdbaf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -0,0 +1,324 @@ +using LibHac; +using LibHac.Fs; + +using static Ryujinx.HLE.Utilities.StringUtils; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class IFileSystem : IpcService + { + private LibHac.Fs.IFileSystem _fileSystem; + + public IFileSystem(LibHac.Fs.IFileSystem provider) + { + _fileSystem = provider; + } + + [Command(0)] + // CreateFile(u32 createOption, u64 size, buffer, 0x19, 0x301> path) + public ResultCode CreateFile(ServiceCtx context) + { + string name = ReadUtf8String(context); + + CreateFileOptions createOption = (CreateFileOptions)context.RequestData.ReadInt32(); + context.RequestData.BaseStream.Position += 4; + + long size = context.RequestData.ReadInt64(); + + try + { + _fileSystem.CreateFile(name, size, createOption); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(1)] + // DeleteFile(buffer, 0x19, 0x301> path) + public ResultCode DeleteFile(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + _fileSystem.DeleteFile(name); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(2)] + // CreateDirectory(buffer, 0x19, 0x301> path) + public ResultCode CreateDirectory(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + _fileSystem.CreateDirectory(name); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(3)] + // DeleteDirectory(buffer, 0x19, 0x301> path) + public ResultCode DeleteDirectory(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + _fileSystem.DeleteDirectory(name); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(4)] + // DeleteDirectoryRecursively(buffer, 0x19, 0x301> path) + public ResultCode DeleteDirectoryRecursively(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + _fileSystem.DeleteDirectoryRecursively(name); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(5)] + // RenameFile(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) + public ResultCode RenameFile(ServiceCtx context) + { + string oldName = ReadUtf8String(context, 0); + string newName = ReadUtf8String(context, 1); + + try + { + _fileSystem.RenameFile(oldName, newName); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(6)] + // RenameDirectory(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) + public ResultCode RenameDirectory(ServiceCtx context) + { + string oldName = ReadUtf8String(context, 0); + string newName = ReadUtf8String(context, 1); + + try + { + _fileSystem.RenameDirectory(oldName, newName); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(7)] + // GetEntryType(buffer, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType + public ResultCode GetEntryType(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + DirectoryEntryType entryType = _fileSystem.GetEntryType(name); + + if (entryType == DirectoryEntryType.Directory || entryType == DirectoryEntryType.File) + { + context.ResponseData.Write((int)entryType); + } + else + { + return ResultCode.PathDoesNotExist; + } + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(8)] + // OpenFile(u32 mode, buffer, 0x19, 0x301> path) -> object file + public ResultCode OpenFile(ServiceCtx context) + { + OpenMode mode = (OpenMode)context.RequestData.ReadInt32(); + + string name = ReadUtf8String(context); + + try + { + LibHac.Fs.IFile file = _fileSystem.OpenFile(name, mode); + + IFile fileInterface = new IFile(file); + + MakeObject(context, fileInterface); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(9)] + // OpenDirectory(u32 filter_flags, buffer, 0x19, 0x301> path) -> object directory + public ResultCode OpenDirectory(ServiceCtx context) + { + OpenDirectoryMode mode = (OpenDirectoryMode)context.RequestData.ReadInt32(); + + string name = ReadUtf8String(context); + + try + { + LibHac.Fs.IDirectory dir = _fileSystem.OpenDirectory(name, mode); + + IDirectory dirInterface = new IDirectory(dir); + + MakeObject(context, dirInterface); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(10)] + // Commit() + public ResultCode Commit(ServiceCtx context) + { + try + { + _fileSystem.Commit(); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(11)] + // GetFreeSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalFreeSpace + public ResultCode GetFreeSpaceSize(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + context.ResponseData.Write(_fileSystem.GetFreeSpaceSize(name)); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(12)] + // GetTotalSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalSize + public ResultCode GetTotalSpaceSize(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + context.ResponseData.Write(_fileSystem.GetTotalSpaceSize(name)); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(13)] + // CleanDirectoryRecursively(buffer, 0x19, 0x301> path) + public ResultCode CleanDirectoryRecursively(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + _fileSystem.CleanDirectoryRecursively(name); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + [Command(14)] + // GetFileTimeStampRaw(buffer, 0x19, 0x301> path) -> bytes<0x20> timestamp + public ResultCode GetFileTimeStampRaw(ServiceCtx context) + { + string name = ReadUtf8String(context); + + try + { + FileTimeStampRaw timestamp = _fileSystem.GetFileTimeStampRaw(name); + + context.ResponseData.Write(timestamp.Created); + context.ResponseData.Write(timestamp.Modified); + context.ResponseData.Write(timestamp.Accessed); + + byte[] data = new byte[8]; + + // is valid? + data[0] = 1; + + context.ResponseData.Write(data); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs new file mode 100644 index 00000000..107599a4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs @@ -0,0 +1,65 @@ +using LibHac; +using Ryujinx.HLE.HOS.Ipc; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class IStorage : IpcService + { + private LibHac.Fs.IStorage _baseStorage; + + public IStorage(LibHac.Fs.IStorage baseStorage) + { + _baseStorage = baseStorage; + } + + [Command(0)] + // Read(u64 offset, u64 length) -> buffer buffer + public ResultCode Read(ServiceCtx context) + { + long offset = context.RequestData.ReadInt64(); + long size = context.RequestData.ReadInt64(); + + if (context.Request.ReceiveBuff.Count > 0) + { + IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0]; + + // Use smaller length to avoid overflows. + if (size > buffDesc.Size) + { + size = buffDesc.Size; + } + + byte[] data = new byte[size]; + + try + { + _baseStorage.Read(data, offset); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + context.Memory.WriteBytes(buffDesc.Position, data); + } + + return ResultCode.Success; + } + + [Command(4)] + // GetSize() -> u64 size + public ResultCode GetSize(ServiceCtx context) + { + try + { + context.ResponseData.Write(_baseStorage.GetSize()); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs new file mode 100644 index 00000000..a0d22595 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -0,0 +1,272 @@ +using LibHac; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; +using System.IO; + +using static Ryujinx.HLE.FileSystem.VirtualFileSystem; +using static Ryujinx.HLE.Utilities.StringUtils; + +namespace Ryujinx.HLE.HOS.Services.Fs +{ + [Service("fsp-srv")] + class IFileSystemProxy : IpcService + { + public IFileSystemProxy(ServiceCtx context) { } + + [Command(1)] + // Initialize(u64, pid) + public ResultCode Initialize(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(8)] + // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer, 0x19, 0x301> path) + // -> object contentFs + public ResultCode OpenFileSystemWithId(ServiceCtx context) + { + FileSystemType fileSystemType = (FileSystemType)context.RequestData.ReadInt32(); + long titleId = context.RequestData.ReadInt64(); + string switchPath = ReadUtf8String(context); + string fullPath = context.Device.FileSystem.SwitchPathToSystemPath(switchPath); + + if (!File.Exists(fullPath)) + { + if (fullPath.Contains(".")) + { + ResultCode result = FileSystemProxyHelper.OpenFileSystemFromInternalFile(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + + return ResultCode.PathDoesNotExist; + } + + FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read); + string extension = Path.GetExtension(fullPath); + + if (extension == ".nca") + { + ResultCode result = FileSystemProxyHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + else if (extension == ".nsp") + { + ResultCode result = FileSystemProxyHelper.OpenNsp(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + + return ResultCode.InvalidInput; + } + + [Command(11)] + // OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer, 0x19, 0x301>) -> object Bis + public ResultCode OpenBisFileSystem(ServiceCtx context) + { + int bisPartitionId = context.RequestData.ReadInt32(); + string partitionString = ReadUtf8String(context); + string bisPartitionPath = string.Empty; + + switch (bisPartitionId) + { + case 29: + bisPartitionPath = SafeNandPath; + break; + case 30: + case 31: + bisPartitionPath = SystemNandPath; + break; + case 32: + bisPartitionPath = UserNandPath; + break; + default: + return ResultCode.InvalidInput; + } + + string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitionPath); + + LocalFileSystem fileSystem = new LocalFileSystem(fullPath); + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [Command(18)] + // OpenSdCardFileSystem() -> object + public ResultCode OpenSdCardFileSystem(ServiceCtx context) + { + string sdCardPath = context.Device.FileSystem.GetSdCardPath(); + + LocalFileSystem fileSystem = new LocalFileSystem(sdCardPath); + + MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem)); + + return ResultCode.Success; + } + + [Command(51)] + // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object saveDataFs + public ResultCode OpenSaveDataFileSystem(ServiceCtx context) + { + ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, false, out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + + [Command(52)] + // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object systemSaveDataFs + public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) + { + ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, false, out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + + [Command(53)] + // OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object + public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context) + { + ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, true, out FileSystemProxy.IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; + } + + [Command(200)] + // OpenDataStorageByCurrentProcess() -> object dataStorage + public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) + { + MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); + + return 0; + } + + [Command(202)] + // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object dataStorage + public ResultCode OpenDataStorageByDataId(ServiceCtx context) + { + StorageId storageId = (StorageId)context.RequestData.ReadByte(); + byte[] padding = context.RequestData.ReadBytes(7); + long titleId = context.RequestData.ReadInt64(); + + ContentType contentType = ContentType.Data; + + StorageId installedStorage = + context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); + + if (installedStorage == StorageId.None) + { + contentType = ContentType.PublicData; + + installedStorage = + context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); + } + + if (installedStorage != StorageId.None) + { + string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, contentType); + string installPath = context.Device.FileSystem.SwitchPathToSystemPath(contentPath); + + if (!string.IsNullOrWhiteSpace(installPath)) + { + string ncaPath = installPath; + + if (File.Exists(ncaPath)) + { + try + { + LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); + Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); + LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); + + MakeObject(context, new FileSystemProxy.IStorage(romfsStorage)); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + else + { + throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`."); + } + } + else + { + throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}."); + } + } + + throw new FileNotFoundException($"System archive with titleid {titleId:x16} was not found on Storage {storageId}. Found in {installedStorage}."); + } + + [Command(203)] + // OpenPatchDataStorageByCurrentProcess() -> object + public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) + { + MakeObject(context, new FileSystemProxy.IStorage(context.Device.FileSystem.RomFs.AsStorage())); + + return ResultCode.Success; + } + + [Command(1005)] + // GetGlobalAccessLogMode() -> u32 logMode + public ResultCode GetGlobalAccessLogMode(ServiceCtx context) + { + int mode = context.Device.System.GlobalAccessLogMode; + + context.ResponseData.Write(mode); + + return ResultCode.Success; + } + + [Command(1006)] + // OutputAccessLogToSdCard(buffer log_text) + public ResultCode OutputAccessLogToSdCard(ServiceCtx context) + { + string message = ReadUtf8StringSend(context); + + // FS ends each line with a newline. Remove it because Ryujinx logging adds its own newline + Logger.PrintAccessLog(LogClass.ServiceFs, message.TrimEnd('\n')); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxyForLoader.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxyForLoader.cs new file mode 100644 index 00000000..a40821b9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxyForLoader.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Fs +{ + [Service("fsp-ldr")] + class IFileSystemProxyForLoader : IpcService + { + public IFileSystemProxyForLoader(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/IProgramRegistry.cs b/Ryujinx.HLE/HOS/Services/Fs/IProgramRegistry.cs new file mode 100644 index 00000000..e11eadf5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/IProgramRegistry.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Fs +{ + [Service("fsp-pr")] + class IProgramRegistry : IpcService + { + public IProgramRegistry(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Fs/ResultCode.cs new file mode 100644 index 00000000..8f87142b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/ResultCode.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Fs +{ + enum ResultCode + { + ModuleId = 2, + ErrorCodeShift = 9, + + Success = 0, + + PathDoesNotExist = (1 << ErrorCodeShift) | ModuleId, + PathAlreadyExists = (2 << ErrorCodeShift) | ModuleId, + PathAlreadyInUse = (7 << ErrorCodeShift) | ModuleId, + PartitionNotFound = (1001 << ErrorCodeShift) | ModuleId, + InvalidInput = (6001 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Fs/Types/FileSystemType.cs b/Ryujinx.HLE/HOS/Services/Fs/Types/FileSystemType.cs new file mode 100644 index 00000000..f12c1661 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Fs/Types/FileSystemType.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Fs +{ + enum FileSystemType + { + Logo = 2, + ContentControl = 3, + ContentManual = 4, + ContentMeta = 5, + ContentData = 6, + ApplicationPackage = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs deleted file mode 100644 index d2e157f5..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs +++ /dev/null @@ -1,144 +0,0 @@ -using LibHac; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using Ryujinx.Common; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.Utilities; -using System.IO; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - static class FileSystemHelper - { - public static ResultCode LoadSaveDataFileSystem(ServiceCtx context, bool readOnly, out IFileSystem loadedFileSystem) - { - loadedFileSystem = null; - - SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64(); - ulong titleId = context.RequestData.ReadUInt64(); - UInt128 userId = context.RequestData.ReadStruct(); - long saveId = context.RequestData.ReadInt64(); - SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte(); - SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, saveSpaceId, userId); - string savePath = context.Device.FileSystem.GetSavePath(context, saveInfo); - - try - { - LocalFileSystem fileSystem = new LocalFileSystem(savePath); - LibHac.Fs.IFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem); - - if (readOnly) - { - saveFileSystem = new ReadOnlyFileSystem(saveFileSystem); - } - - loadedFileSystem = new IFileSystem(saveFileSystem); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - public static ResultCode OpenNsp(ServiceCtx context, string pfsPath, out IFileSystem openedFileSystem) - { - openedFileSystem = null; - - try - { - LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); - PartitionFileSystem nsp = new PartitionFileSystem(storage); - - ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - - openedFileSystem = new IFileSystem(nsp); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - public static ResultCode OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem) - { - openedFileSystem = null; - - try - { - Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); - - if (!nca.SectionExists(NcaSectionType.Data)) - { - return ResultCode.PartitionNotFound; - } - - LibHac.Fs.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); - - openedFileSystem = new IFileSystem(fileSystem); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - public static ResultCode OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath, out IFileSystem openedFileSystem) - { - openedFileSystem = null; - - DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent; - - while (string.IsNullOrWhiteSpace(archivePath.Extension)) - { - archivePath = archivePath.Parent; - } - - if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName)) - { - FileStream pfsFile = new FileStream( - archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), - FileMode.Open, - FileAccess.Read); - - try - { - PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); - - ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - - string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); - - if (nsp.FileExists(filename)) - { - return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage(), out openedFileSystem); - } - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - } - - return ResultCode.PathDoesNotExist; - } - - public static void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet) - { - foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) - { - Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); - - if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) - { - keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemType.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemType.cs deleted file mode 100644 index 4b2d0ccd..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - enum FileSystemType - { - Logo = 2, - ContentControl = 3, - ContentManual = 4, - ContentMeta = 5, - ContentData = 6, - ApplicationPackage = 7 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs deleted file mode 100644 index 57d9142c..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs +++ /dev/null @@ -1,84 +0,0 @@ -using LibHac; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - class IDirectory : IpcService - { - private const int DirectoryEntrySize = 0x310; - - private IEnumerator _enumerator; - - private LibHac.Fs.IDirectory _baseDirectory; - - public IDirectory(LibHac.Fs.IDirectory directory) - { - _baseDirectory = directory; - _enumerator = directory.Read().GetEnumerator(); - } - - [Command(0)] - // Read() -> (u64 count, buffer entries) - public ResultCode Read(ServiceCtx context) - { - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferLen = context.Request.ReceiveBuff[0].Size; - - int maxReadCount = (int)(bufferLen / DirectoryEntrySize); - int readCount = 0; - - try - { - while (readCount < maxReadCount && _enumerator.MoveNext()) - { - long position = bufferPosition + readCount * DirectoryEntrySize; - - WriteDirectoryEntry(context, position, _enumerator.Current); - - readCount++; - } - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - context.ResponseData.Write((long)readCount); - - return ResultCode.Success; - } - - private void WriteDirectoryEntry(ServiceCtx context, long position, LibHac.Fs.DirectoryEntry entry) - { - for (int offset = 0; offset < 0x300; offset += 8) - { - context.Memory.WriteInt64(position + offset, 0); - } - - byte[] nameBuffer = Encoding.UTF8.GetBytes(entry.Name); - - context.Memory.WriteBytes(position, nameBuffer); - - context.Memory.WriteInt32(position + 0x300, (int)entry.Attributes); - context.Memory.WriteInt32(position + 0x304, (byte)entry.Type); - context.Memory.WriteInt64(position + 0x308, entry.Size); - } - - [Command(1)] - // GetEntryCount() -> u64 - public ResultCode GetEntryCount(ServiceCtx context) - { - try - { - context.ResponseData.Write((long)_baseDirectory.GetEntryCount()); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs deleted file mode 100644 index 7200611b..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs +++ /dev/null @@ -1,136 +0,0 @@ -using LibHac; -using LibHac.Fs; -using System; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - class IFile : IpcService, IDisposable - { - private LibHac.Fs.IFile _baseFile; - - public IFile(LibHac.Fs.IFile baseFile) - { - _baseFile = baseFile; - } - - [Command(0)] - // Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer out_buf) - public ResultCode Read(ServiceCtx context) - { - long position = context.Request.ReceiveBuff[0].Position; - - ReadOption readOption = (ReadOption)context.RequestData.ReadInt32(); - context.RequestData.BaseStream.Position += 4; - - long offset = context.RequestData.ReadInt64(); - long size = context.RequestData.ReadInt64(); - - byte[] data = new byte[size]; - int readSize; - - try - { - readSize = _baseFile.Read(data, offset, readOption); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - context.Memory.WriteBytes(position, data); - - context.ResponseData.Write((long)readSize); - - return ResultCode.Success; - } - - [Command(1)] - // Write(u32 writeOption, u64 offset, u64 size, buffer) - public ResultCode Write(ServiceCtx context) - { - long position = context.Request.SendBuff[0].Position; - - WriteOption writeOption = (WriteOption)context.RequestData.ReadInt32(); - context.RequestData.BaseStream.Position += 4; - - long offset = context.RequestData.ReadInt64(); - long size = context.RequestData.ReadInt64(); - - byte[] data = context.Memory.ReadBytes(position, size); - - try - { - _baseFile.Write(data, offset, writeOption); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(2)] - // Flush() - public ResultCode Flush(ServiceCtx context) - { - try - { - _baseFile.Flush(); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(3)] - // SetSize(u64 size) - public ResultCode SetSize(ServiceCtx context) - { - try - { - long size = context.RequestData.ReadInt64(); - - _baseFile.SetSize(size); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(4)] - // GetSize() -> u64 fileSize - public ResultCode GetSize(ServiceCtx context) - { - try - { - context.ResponseData.Write(_baseFile.GetSize()); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _baseFile?.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs deleted file mode 100644 index bcdc6fc3..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs +++ /dev/null @@ -1,324 +0,0 @@ -using LibHac; -using LibHac.Fs; - -using static Ryujinx.HLE.Utilities.StringUtils; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - class IFileSystem : IpcService - { - private LibHac.Fs.IFileSystem _fileSystem; - - public IFileSystem(LibHac.Fs.IFileSystem provider) - { - _fileSystem = provider; - } - - [Command(0)] - // CreateFile(u32 createOption, u64 size, buffer, 0x19, 0x301> path) - public ResultCode CreateFile(ServiceCtx context) - { - string name = ReadUtf8String(context); - - CreateFileOptions createOption = (CreateFileOptions)context.RequestData.ReadInt32(); - context.RequestData.BaseStream.Position += 4; - - long size = context.RequestData.ReadInt64(); - - try - { - _fileSystem.CreateFile(name, size, createOption); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(1)] - // DeleteFile(buffer, 0x19, 0x301> path) - public ResultCode DeleteFile(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - _fileSystem.DeleteFile(name); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(2)] - // CreateDirectory(buffer, 0x19, 0x301> path) - public ResultCode CreateDirectory(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - _fileSystem.CreateDirectory(name); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(3)] - // DeleteDirectory(buffer, 0x19, 0x301> path) - public ResultCode DeleteDirectory(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - _fileSystem.DeleteDirectory(name); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(4)] - // DeleteDirectoryRecursively(buffer, 0x19, 0x301> path) - public ResultCode DeleteDirectoryRecursively(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - _fileSystem.DeleteDirectoryRecursively(name); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(5)] - // RenameFile(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) - public ResultCode RenameFile(ServiceCtx context) - { - string oldName = ReadUtf8String(context, 0); - string newName = ReadUtf8String(context, 1); - - try - { - _fileSystem.RenameFile(oldName, newName); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(6)] - // RenameDirectory(buffer, 0x19, 0x301> oldPath, buffer, 0x19, 0x301> newPath) - public ResultCode RenameDirectory(ServiceCtx context) - { - string oldName = ReadUtf8String(context, 0); - string newName = ReadUtf8String(context, 1); - - try - { - _fileSystem.RenameDirectory(oldName, newName); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(7)] - // GetEntryType(buffer, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType - public ResultCode GetEntryType(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - DirectoryEntryType entryType = _fileSystem.GetEntryType(name); - - if (entryType == DirectoryEntryType.Directory || entryType == DirectoryEntryType.File) - { - context.ResponseData.Write((int)entryType); - } - else - { - return ResultCode.PathDoesNotExist; - } - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(8)] - // OpenFile(u32 mode, buffer, 0x19, 0x301> path) -> object file - public ResultCode OpenFile(ServiceCtx context) - { - OpenMode mode = (OpenMode)context.RequestData.ReadInt32(); - - string name = ReadUtf8String(context); - - try - { - LibHac.Fs.IFile file = _fileSystem.OpenFile(name, mode); - - IFile fileInterface = new IFile(file); - - MakeObject(context, fileInterface); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(9)] - // OpenDirectory(u32 filter_flags, buffer, 0x19, 0x301> path) -> object directory - public ResultCode OpenDirectory(ServiceCtx context) - { - OpenDirectoryMode mode = (OpenDirectoryMode)context.RequestData.ReadInt32(); - - string name = ReadUtf8String(context); - - try - { - LibHac.Fs.IDirectory dir = _fileSystem.OpenDirectory(name, mode); - - IDirectory dirInterface = new IDirectory(dir); - - MakeObject(context, dirInterface); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(10)] - // Commit() - public ResultCode Commit(ServiceCtx context) - { - try - { - _fileSystem.Commit(); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(11)] - // GetFreeSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalFreeSpace - public ResultCode GetFreeSpaceSize(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - context.ResponseData.Write(_fileSystem.GetFreeSpaceSize(name)); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(12)] - // GetTotalSpaceSize(buffer, 0x19, 0x301> path) -> u64 totalSize - public ResultCode GetTotalSpaceSize(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - context.ResponseData.Write(_fileSystem.GetTotalSpaceSize(name)); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(13)] - // CleanDirectoryRecursively(buffer, 0x19, 0x301> path) - public ResultCode CleanDirectoryRecursively(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - _fileSystem.CleanDirectoryRecursively(name); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - [Command(14)] - // GetFileTimeStampRaw(buffer, 0x19, 0x301> path) -> bytes<0x20> timestamp - public ResultCode GetFileTimeStampRaw(ServiceCtx context) - { - string name = ReadUtf8String(context); - - try - { - FileTimeStampRaw timestamp = _fileSystem.GetFileTimeStampRaw(name); - - context.ResponseData.Write(timestamp.Created); - context.ResponseData.Write(timestamp.Modified); - context.ResponseData.Write(timestamp.Accessed); - - byte[] data = new byte[8]; - - // is valid? - data[0] = 1; - - context.ResponseData.Write(data); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs deleted file mode 100644 index 43f5d647..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ /dev/null @@ -1,271 +0,0 @@ -using LibHac; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; -using System.IO; - -using static Ryujinx.HLE.FileSystem.VirtualFileSystem; -using static Ryujinx.HLE.Utilities.StringUtils; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - [Service("fsp-srv")] - class IFileSystemProxy : IpcService - { - public IFileSystemProxy(ServiceCtx context) { } - - [Command(1)] - // Initialize(u64, pid) - public ResultCode Initialize(ServiceCtx context) - { - return ResultCode.Success; - } - - [Command(8)] - // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer, 0x19, 0x301> path) - // -> object contentFs - public ResultCode OpenFileSystemWithId(ServiceCtx context) - { - FileSystemType fileSystemType = (FileSystemType)context.RequestData.ReadInt32(); - long titleId = context.RequestData.ReadInt64(); - string switchPath = ReadUtf8String(context); - string fullPath = context.Device.FileSystem.SwitchPathToSystemPath(switchPath); - - if (!File.Exists(fullPath)) - { - if (fullPath.Contains(".")) - { - ResultCode result = FileSystemHelper.OpenFileSystemFromInternalFile(context, fullPath, out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - - return ResultCode.PathDoesNotExist; - } - - FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read); - string extension = Path.GetExtension(fullPath); - - if (extension == ".nca") - { - ResultCode result = FileSystemHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - else if (extension == ".nsp") - { - ResultCode result = FileSystemHelper.OpenNsp(context, fullPath, out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - - return ResultCode.InvalidInput; - } - - [Command(11)] - // OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer, 0x19, 0x301>) -> object Bis - public ResultCode OpenBisFileSystem(ServiceCtx context) - { - int bisPartitionId = context.RequestData.ReadInt32(); - string partitionString = ReadUtf8String(context); - string bisPartitionPath = string.Empty; - - switch (bisPartitionId) - { - case 29: - bisPartitionPath = SafeNandPath; - break; - case 30: - case 31: - bisPartitionPath = SystemNandPath; - break; - case 32: - bisPartitionPath = UserNandPath; - break; - default: - return ResultCode.InvalidInput; - } - - string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitionPath); - - LocalFileSystem fileSystem = new LocalFileSystem(fullPath); - - MakeObject(context, new IFileSystem(fileSystem)); - - return ResultCode.Success; - } - - [Command(18)] - // OpenSdCardFileSystem() -> object - public ResultCode OpenSdCardFileSystem(ServiceCtx context) - { - string sdCardPath = context.Device.FileSystem.GetSdCardPath(); - - LocalFileSystem fileSystem = new LocalFileSystem(sdCardPath); - - MakeObject(context, new IFileSystem(fileSystem)); - - return ResultCode.Success; - } - - [Command(51)] - // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object saveDataFs - public ResultCode OpenSaveDataFileSystem(ServiceCtx context) - { - ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, false, out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - - [Command(52)] - // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object systemSaveDataFs - public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) - { - ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, false, out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - - [Command(53)] - // OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object - public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context) - { - ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, true, out IFileSystem fileSystem); - - if (result == ResultCode.Success) - { - MakeObject(context, fileSystem); - } - - return result; - } - - [Command(200)] - // OpenDataStorageByCurrentProcess() -> object dataStorage - public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) - { - MakeObject(context, new IStorage(context.Device.FileSystem.RomFs.AsStorage())); - - return 0; - } - - [Command(202)] - // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object dataStorage - public ResultCode OpenDataStorageByDataId(ServiceCtx context) - { - StorageId storageId = (StorageId)context.RequestData.ReadByte(); - byte[] padding = context.RequestData.ReadBytes(7); - long titleId = context.RequestData.ReadInt64(); - - ContentType contentType = ContentType.Data; - - StorageId installedStorage = - context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); - - if (installedStorage == StorageId.None) - { - contentType = ContentType.PublicData; - - installedStorage = - context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); - } - - if (installedStorage != StorageId.None) - { - string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, contentType); - string installPath = context.Device.FileSystem.SwitchPathToSystemPath(contentPath); - - if (!string.IsNullOrWhiteSpace(installPath)) - { - string ncaPath = installPath; - - if (File.Exists(ncaPath)) - { - try - { - LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); - Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); - LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); - - MakeObject(context, new IStorage(romfsStorage)); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - else - { - throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`."); - } - } - else - { - throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}."); - } - } - - throw new FileNotFoundException($"System archive with titleid {titleId:x16} was not found on Storage {storageId}. Found in {installedStorage}."); - } - - [Command(203)] - // OpenPatchDataStorageByCurrentProcess() -> object - public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) - { - MakeObject(context, new IStorage(context.Device.FileSystem.RomFs.AsStorage())); - - return ResultCode.Success; - } - - [Command(1005)] - // GetGlobalAccessLogMode() -> u32 logMode - public ResultCode GetGlobalAccessLogMode(ServiceCtx context) - { - int mode = context.Device.System.GlobalAccessLogMode; - - context.ResponseData.Write(mode); - - return ResultCode.Success; - } - - [Command(1006)] - // OutputAccessLogToSdCard(buffer log_text) - public ResultCode OutputAccessLogToSdCard(ServiceCtx context) - { - string message = ReadUtf8StringSend(context); - - // FS ends each line with a newline. Remove it because Ryujinx logging adds its own newline - Logger.PrintAccessLog(LogClass.ServiceFs, message.TrimEnd('\n')); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs deleted file mode 100644 index d13a12db..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs +++ /dev/null @@ -1,65 +0,0 @@ -using LibHac; -using Ryujinx.HLE.HOS.Ipc; - -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - class IStorage : IpcService - { - private LibHac.Fs.IStorage _baseStorage; - - public IStorage(LibHac.Fs.IStorage baseStorage) - { - _baseStorage = baseStorage; - } - - [Command(0)] - // Read(u64 offset, u64 length) -> buffer buffer - public ResultCode Read(ServiceCtx context) - { - long offset = context.RequestData.ReadInt64(); - long size = context.RequestData.ReadInt64(); - - if (context.Request.ReceiveBuff.Count > 0) - { - IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0]; - - // Use smaller length to avoid overflows. - if (size > buffDesc.Size) - { - size = buffDesc.Size; - } - - byte[] data = new byte[size]; - - try - { - _baseStorage.Read(data, offset); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - context.Memory.WriteBytes(buffDesc.Position, data); - } - - return ResultCode.Success; - } - - [Command(4)] - // GetSize() -> u64 size - public ResultCode GetSize(ServiceCtx context) - { - try - { - context.ResponseData.Write(_baseStorage.GetSize()); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/ResultCode.cs b/Ryujinx.HLE/HOS/Services/FspSrv/ResultCode.cs deleted file mode 100644 index b2be9293..00000000 --- a/Ryujinx.HLE/HOS/Services/FspSrv/ResultCode.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.FspSrv -{ - enum ResultCode - { - ModuleId = 2, - ErrorCodeShift = 9, - - Success = 0, - - PathDoesNotExist = (1 << ErrorCodeShift) | ModuleId, - PathAlreadyExists = (2 << ErrorCodeShift) | ModuleId, - PathAlreadyInUse = (7 << ErrorCodeShift) | ModuleId, - PartitionNotFound = (1001 << ErrorCodeShift) | ModuleId, - InvalidInput = (6001 << ErrorCodeShift) | ModuleId - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs deleted file mode 100644 index b96f0d05..00000000 --- a/Ryujinx.HLE/HOS/Services/Glue/ApplicationLaunchProperty.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.Utilities; -using System; - -namespace Ryujinx.HLE.HOS.Services.Glue -{ - class ApplicationLaunchProperty - { - public long TitleId; - public int Version; - public byte BaseGameStorageId; - public byte UpdateGameStorageId; - public short Padding; - - public static ApplicationLaunchProperty Default - { - get - { - return new ApplicationLaunchProperty - { - TitleId = 0x00, - Version = 0x00, - BaseGameStorageId = (byte)StorageId.NandSystem, - UpdateGameStorageId = (byte)StorageId.None - }; - } - } - - public static ApplicationLaunchProperty GetByPid(ServiceCtx context) - { - // TODO: Handle ApplicationLaunchProperty as array when pid will be supported and return the right item. - // For now we can hardcode values, and fix it after GetApplicationLaunchProperty is implemented. - - return new ApplicationLaunchProperty - { - TitleId = BitConverter.ToInt64(StringUtils.HexToBytes(context.Device.System.TitleID), 0), - Version = 0x00, - BaseGameStorageId = (byte)StorageId.NandSystem, - UpdateGameStorageId = (byte)StorageId.None - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Grc/IGrcService.cs b/Ryujinx.HLE/HOS/Services/Grc/IGrcService.cs new file mode 100644 index 00000000..90646b40 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Grc/IGrcService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Grc +{ + [Service("grc:c")] // 4.0.0+ + class IGrcService : IpcService + { + public IGrcService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Grc/IRemoteVideoTransfer.cs b/Ryujinx.HLE/HOS/Services/Grc/IRemoteVideoTransfer.cs new file mode 100644 index 00000000..edb1d64e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Grc/IRemoteVideoTransfer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Grc +{ + [Service("grc:d")] // 6.0.0+ + class IRemoteVideoTransfer : IpcService + { + public IRemoteVideoTransfer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs b/Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs deleted file mode 100644 index b2581202..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Hid -{ - public enum HidNpadJoyAssignmentMode - { - Dual, - Single - } - - public enum HidNpadHandheldActivationMode - { - Dual, - Single, - None - } - - public enum HidNpadJoyDeviceType - { - Left, - Right - } - - public enum HidNpadJoyHoldType - { - Vertical, - Horizontal - } - - [Flags] - public enum HidNpadStyle - { - None, - FullKey = 1 << 0, - Handheld = 1 << 1, - Dual = 1 << 2, - Left = 1 << 3, - Right = 1 << 4, - Invalid = 1 << 5 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs new file mode 100644 index 00000000..c89ea306 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs @@ -0,0 +1,46 @@ +using Ryujinx.HLE.Input; +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.HidServer +{ + static class HidUtils + { + public static ControllerId GetIndexFromNpadIdType(HidNpadIdType npadIdType) + { + switch (npadIdType) + { + case HidNpadIdType.Player1: return ControllerId.ControllerPlayer1; + case HidNpadIdType.Player2: return ControllerId.ControllerPlayer2; + case HidNpadIdType.Player3: return ControllerId.ControllerPlayer3; + case HidNpadIdType.Player4: return ControllerId.ControllerPlayer4; + case HidNpadIdType.Player5: return ControllerId.ControllerPlayer5; + case HidNpadIdType.Player6: return ControllerId.ControllerPlayer6; + case HidNpadIdType.Player7: return ControllerId.ControllerPlayer7; + case HidNpadIdType.Player8: return ControllerId.ControllerPlayer8; + case HidNpadIdType.Handheld: return ControllerId.ControllerHandheld; + case HidNpadIdType.Unknown: return ControllerId.ControllerUnknown; + + default: throw new ArgumentOutOfRangeException(nameof(npadIdType)); + } + } + + public static HidNpadIdType GetNpadIdTypeFromIndex(ControllerId index) + { + switch (index) + { + case ControllerId.ControllerPlayer1: return HidNpadIdType.Player1; + case ControllerId.ControllerPlayer2: return HidNpadIdType.Player2; + case ControllerId.ControllerPlayer3: return HidNpadIdType.Player3; + case ControllerId.ControllerPlayer4: return HidNpadIdType.Player4; + case ControllerId.ControllerPlayer5: return HidNpadIdType.Player5; + case ControllerId.ControllerPlayer6: return HidNpadIdType.Player6; + case ControllerId.ControllerPlayer7: return HidNpadIdType.Player7; + case ControllerId.ControllerPlayer8: return HidNpadIdType.Player8; + case ControllerId.ControllerHandheld: return HidNpadIdType.Handheld; + case ControllerId.ControllerUnknown: return HidNpadIdType.Unknown; + + default: throw new ArgumentOutOfRangeException(nameof(index)); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IActiveVibrationDeviceList.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IActiveVibrationDeviceList.cs new file mode 100644 index 00000000..4c2050f1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IActiveVibrationDeviceList.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.HidServer +{ + class IActiveApplicationDeviceList : IpcService + { + public IActiveApplicationDeviceList() { } + + [Command(0)] + // ActivateVibrationDevice(nn::hid::VibrationDeviceHandle) + public ResultCode ActivateVibrationDevice(ServiceCtx context) + { + int vibrationDeviceHandle = context.RequestData.ReadInt32(); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs new file mode 100644 index 00000000..2c3a6500 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs @@ -0,0 +1,31 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Memory; +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.HidServer +{ + class IAppletResource : IpcService + { + private KSharedMemory _hidSharedMem; + + public IAppletResource(KSharedMemory hidSharedMem) + { + _hidSharedMem = hidSharedMem; + } + + [Command(0)] + // GetSharedMemoryHandle() -> handle + public ResultCode GetSharedMemoryHandle(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs b/Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs deleted file mode 100644 index 7c7ebcc4..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - public struct HidSensorFusionParameters - { - public float RevisePower; - public float ReviseRange; - } - - public struct HidAccelerometerParameters - { - public float X; - public float Y; - } - - public enum HidGyroscopeZeroDriftMode - { - Loose, - Standard, - Tight - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs deleted file mode 100644 index fd540c7c..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Ryujinx.HLE.Input; -using System; - -namespace Ryujinx.HLE.HOS.Services.Hid -{ - static class HidUtils - { - public static ControllerId GetIndexFromNpadIdType(NpadIdType npadIdType) - { - switch (npadIdType) - { - case NpadIdType.Player1: return ControllerId.ControllerPlayer1; - case NpadIdType.Player2: return ControllerId.ControllerPlayer2; - case NpadIdType.Player3: return ControllerId.ControllerPlayer3; - case NpadIdType.Player4: return ControllerId.ControllerPlayer4; - case NpadIdType.Player5: return ControllerId.ControllerPlayer5; - case NpadIdType.Player6: return ControllerId.ControllerPlayer6; - case NpadIdType.Player7: return ControllerId.ControllerPlayer7; - case NpadIdType.Player8: return ControllerId.ControllerPlayer8; - case NpadIdType.Handheld: return ControllerId.ControllerHandheld; - case NpadIdType.Unknown: return ControllerId.ControllerUnknown; - - default: throw new ArgumentOutOfRangeException(nameof(npadIdType)); - } - } - - public static NpadIdType GetNpadIdTypeFromIndex(ControllerId index) - { - switch (index) - { - case ControllerId.ControllerPlayer1: return NpadIdType.Player1; - case ControllerId.ControllerPlayer2: return NpadIdType.Player2; - case ControllerId.ControllerPlayer3: return NpadIdType.Player3; - case ControllerId.ControllerPlayer4: return NpadIdType.Player4; - case ControllerId.ControllerPlayer5: return NpadIdType.Player5; - case ControllerId.ControllerPlayer6: return NpadIdType.Player6; - case ControllerId.ControllerPlayer7: return NpadIdType.Player7; - case ControllerId.ControllerPlayer8: return NpadIdType.Player8; - case ControllerId.ControllerHandheld: return NpadIdType.Handheld; - case ControllerId.ControllerUnknown: return NpadIdType.Unknown; - - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidVibration.cs b/Ryujinx.HLE/HOS/Services/Hid/HidVibration.cs deleted file mode 100644 index 635c356c..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/HidVibration.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - public enum HidVibrationDeviceType - { - None, - LinearResonantActuator - } - - public enum HidVibrationDevicePosition - { - None, - Left, - Right - } - - public struct HidVibrationDeviceValue - { - public HidVibrationDeviceType DeviceType; - public HidVibrationDevicePosition Position; - } - - public struct HidVibrationValue - { - public float AmplitudeLow; - public float FrequencyLow; - public float AmplitudeHigh; - public float FrequencyHigh; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs deleted file mode 100644 index 8aa623ee..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - class IActiveApplicationDeviceList : IpcService - { - public IActiveApplicationDeviceList() { } - - [Command(0)] - // ActivateVibrationDevice(nn::hid::VibrationDeviceHandle) - public ResultCode ActivateVibrationDevice(ServiceCtx context) - { - int vibrationDeviceHandle = context.RequestData.ReadInt32(); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs deleted file mode 100644 index 437ef082..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Memory; -using System; - -namespace Ryujinx.HLE.HOS.Services.Hid -{ - class IAppletResource : IpcService - { - private KSharedMemory _hidSharedMem; - - public IAppletResource(KSharedMemory hidSharedMem) - { - _hidSharedMem = hidSharedMem; - } - - [Command(0)] - // GetSharedMemoryHandle() -> handle - public ResultCode GetSharedMemoryHandle(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidDebugServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidDebugServer.cs new file mode 100644 index 00000000..adaaa012 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidDebugServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Service("hid:dbg")] + class IHidDebugServer : IpcService + { + public IHidDebugServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 9adc08c1..1af9baf8 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -2,6 +2,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Hid.HidServer; using Ryujinx.HLE.Input; using System; diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs new file mode 100644 index 00000000..019e9954 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Service("hid:sys")] + class IHidSystemServer : IpcService + { + public IHidSystemServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidbusServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidbusServer.cs new file mode 100644 index 00000000..bfd1d4dc --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidbusServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Service("hidbus")] + class IHidbusServer : IpcService + { + public IHidbusServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/ISystemServer.cs b/Ryujinx.HLE/HOS/Services/Hid/ISystemServer.cs new file mode 100644 index 00000000..71353344 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/ISystemServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Service("xcd:sys")] + class ISystemServer : IpcService + { + public ISystemServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs index d2991d0f..cd571f11 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Services.Hid.HidServer; using Ryujinx.HLE.Input; using System; @@ -56,11 +57,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle public ResultCode GetNpadIrCameraHandle(ServiceCtx context) { - NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32(); + HidNpadIdType npadIdType = (HidNpadIdType)context.RequestData.ReadUInt32(); - if (npadIdType > NpadIdType.Player8 && - npadIdType != NpadIdType.Unknown && - npadIdType != NpadIdType.Handheld) + if (npadIdType > HidNpadIdType.Player8 && + npadIdType != HidNpadIdType.Unknown && + npadIdType != HidNpadIdType.Handheld) { return ResultCode.NpadIdOutOfRange; } diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorSystemServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorSystemServer.cs new file mode 100644 index 00000000..99fcd541 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorSystemServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Irs +{ + [Service("irs:sys")] + class IIrSensorSystemServer : IpcService + { + public IIrSensorSystemServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/NpadIdType.cs b/Ryujinx.HLE/HOS/Services/Hid/NpadIdType.cs deleted file mode 100644 index 5f6a68cb..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/NpadIdType.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - public enum NpadIdType - { - Player1 = 0, - Player2 = 1, - Player3 = 2, - Player4 = 3, - Player5 = 4, - Player6 = 5, - Player7 = 6, - Player8 = 7, - Unknown = 16, - Handheld = 32 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs new file mode 100644 index 00000000..0aa8334d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidNpadHandheldActivationMode + { + Dual, + Single, + None + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs new file mode 100644 index 00000000..9a3989de --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidNpadIdType + { + Player1 = 0, + Player2 = 1, + Player3 = 2, + Player4 = 3, + Player5 = 4, + Player6 = 5, + Player7 = 6, + Player8 = 7, + Unknown = 16, + Handheld = 32 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs new file mode 100644 index 00000000..a2e22661 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidNpadJoyAssignmentMode + { + Dual, + Single + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs new file mode 100644 index 00000000..d0b34def --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidNpadJoyDeviceType + { + Left, + Right + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs new file mode 100644 index 00000000..3bd3aa91 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidNpadJoyHoldType + { + Vertical, + Horizontal + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs new file mode 100644 index 00000000..93717acf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs @@ -0,0 +1,16 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + public enum HidNpadStyle + { + None, + FullKey = 1 << 0, + Handheld = 1 << 1, + Dual = 1 << 2, + Left = 1 << 3, + Right = 1 << 4, + Invalid = 1 << 5 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs new file mode 100644 index 00000000..fe7e4cc9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct HidAccelerometerParameters + { + public float X; + public float Y; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs new file mode 100644 index 00000000..cd3aa318 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidGyroscopeZeroDriftMode + { + Loose, + Standard, + Tight + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs new file mode 100644 index 00000000..cadf5ec0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct HidSensorFusionParameters + { + public float RevisePower; + public float ReviseRange; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs new file mode 100644 index 00000000..0ab84af3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidVibrationDevicePosition + { + None, + Left, + Right + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs new file mode 100644 index 00000000..cf9e6498 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum HidVibrationDeviceType + { + None, + LinearResonantActuator + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs new file mode 100644 index 00000000..7905ecfd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct HidVibrationDeviceValue + { + public HidVibrationDeviceType DeviceType; + public HidVibrationDevicePosition Position; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs new file mode 100644 index 00000000..7211396e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct HidVibrationValue + { + public float AmplitudeLow; + public float FrequencyLow; + public float AmplitudeHigh; + public float FrequencyHigh; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ins/IReceiverManager.cs b/Ryujinx.HLE/HOS/Services/Ins/IReceiverManager.cs new file mode 100644 index 00000000..34d4bdfd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ins/IReceiverManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ins +{ + [Service("ins:r")] + class IReceiverManager : IpcService + { + public IReceiverManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ins/ISenderManager.cs b/Ryujinx.HLE/HOS/Services/Ins/ISenderManager.cs new file mode 100644 index 00000000..38a95ee7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ins/ISenderManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ins +{ + [Service("ins:s")] + class ISenderManager : IpcService + { + public ISenderManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs b/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs new file mode 100644 index 00000000..de84095e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Lbl +{ + [Service("lbl")] + class ILblController : IpcService + { + public ILblController(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldn/IMonitorServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Ldn/IMonitorServiceCreator.cs new file mode 100644 index 00000000..09dfa78f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldn/IMonitorServiceCreator.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldn +{ + [Service("ldn:m")] + class IMonitorServiceCreator : IpcService + { + public IMonitorServiceCreator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldn/ISystemServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Ldn/ISystemServiceCreator.cs new file mode 100644 index 00000000..b4dac449 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldn/ISystemServiceCreator.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldn +{ + [Service("ldn:s")] + class ISystemServiceCreator : IpcService + { + public ISystemServiceCreator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs new file mode 100644 index 00000000..052727dd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldn/IUserServiceCreator.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldn +{ + [Service("ldn:u")] + class IUserServiceCreator : IpcService + { + public IUserServiceCreator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs new file mode 100644 index 00000000..9c9ee3be --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/IServiceCreator.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p +{ + [Service("lp2p:app")] // 9.0.0+ + [Service("lp2p:sys")] // 9.0.0+ + class IServiceCreator : IpcService + { + public IServiceCreator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IDebugMonitorInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IDebugMonitorInterface.cs new file mode 100644 index 00000000..d87234da --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/IDebugMonitorInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + [Service("ldr:dmnt")] + class IDebugMonitorInterface : IpcService + { + public IDebugMonitorInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IProcessManagerInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IProcessManagerInterface.cs new file mode 100644 index 00000000..9f5b5e35 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/IProcessManagerInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + [Service("ldr:pm")] + class IProcessManagerInterface : IpcService + { + public IProcessManagerInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs index 748a600d..b5ef0f07 100644 --- a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs @@ -1,6 +1,5 @@ using ARMeilleure.Memory; using Ryujinx.Common; -using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; @@ -9,91 +8,12 @@ using Ryujinx.HLE.Utilities; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Security.Cryptography; namespace Ryujinx.HLE.HOS.Services.Ldr { - [StructLayout(LayoutKind.Explicit, Size = 0x350)] - unsafe struct NrrHeader - { - [FieldOffset(0)] - public uint Magic; - - [FieldOffset(0x10)] - public ulong TitleIdMask; - - [FieldOffset(0x18)] - public ulong TitleIdPattern; - - [FieldOffset(0x30)] - public fixed byte Modulus[0x100]; - - [FieldOffset(0x130)] - public fixed byte FixedKeySignature[0x100]; - - [FieldOffset(0x230)] - public fixed byte NrrSignature[0x100]; - - [FieldOffset(0x330)] - public ulong TitleIdMin; - - [FieldOffset(0x338)] - public uint NrrSize; - - [FieldOffset(0x340)] - public uint HashOffset; - - [FieldOffset(0x344)] - public uint HashCount; - } - - class NrrInfo - { - public NrrHeader Header { get; private set; } - public List Hashes { get; private set; } - public long NrrAddress { get; private set; } - - public NrrInfo(long nrrAddress, NrrHeader header, List hashes) - { - NrrAddress = nrrAddress; - Header = header; - Hashes = hashes; - } - } - - class NroInfo - { - public NxRelocatableObject Executable { get; private set; } - - public byte[] Hash { get; private set; } - public ulong NroAddress { get; private set; } - public ulong NroSize { get; private set; } - public ulong BssAddress { get; private set; } - public ulong BssSize { get; private set; } - public ulong TotalSize { get; private set; } - public ulong NroMappedAddress { get; set; } - - public NroInfo( - NxRelocatableObject executable, - byte[] hash, - ulong nroAddress, - ulong nroSize, - ulong bssAddress, - ulong bssSize, - ulong totalSize) - { - Executable = executable; - Hash = hash; - NroAddress = nroAddress; - NroSize = nroSize; - BssAddress = bssAddress; - BssSize = bssSize; - TotalSize = totalSize; - } - } - [Service("ldr:ro")] + [Service("ro:1")] // 7.0.0+ class IRoInterface : IpcService { private const int MaxNrr = 0x40; diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IShellInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IShellInterface.cs new file mode 100644 index 00000000..856aec52 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/IShellInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + [Service("ldr:shel")] + class IShellInterface : IpcService + { + public IShellInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/Types/NroInfo.cs b/Ryujinx.HLE/HOS/Services/Ldr/Types/NroInfo.cs new file mode 100644 index 00000000..c65d5413 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/Types/NroInfo.cs @@ -0,0 +1,35 @@ +using Ryujinx.HLE.Loaders.Executables; + +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + class NroInfo + { + public NxRelocatableObject Executable { get; private set; } + + public byte[] Hash { get; private set; } + public ulong NroAddress { get; private set; } + public ulong NroSize { get; private set; } + public ulong BssAddress { get; private set; } + public ulong BssSize { get; private set; } + public ulong TotalSize { get; private set; } + public ulong NroMappedAddress { get; set; } + + public NroInfo( + NxRelocatableObject executable, + byte[] hash, + ulong nroAddress, + ulong nroSize, + ulong bssAddress, + ulong bssSize, + ulong totalSize) + { + Executable = executable; + Hash = hash; + NroAddress = nroAddress; + NroSize = nroSize; + BssAddress = bssAddress; + BssSize = bssSize; + TotalSize = totalSize; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrHeader.cs b/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrHeader.cs new file mode 100644 index 00000000..a0764d1f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrHeader.cs @@ -0,0 +1,38 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + [StructLayout(LayoutKind.Explicit, Size = 0x350)] + unsafe struct NrrHeader + { + [FieldOffset(0)] + public uint Magic; + + [FieldOffset(0x10)] + public ulong TitleIdMask; + + [FieldOffset(0x18)] + public ulong TitleIdPattern; + + [FieldOffset(0x30)] + public fixed byte Modulus[0x100]; + + [FieldOffset(0x130)] + public fixed byte FixedKeySignature[0x100]; + + [FieldOffset(0x230)] + public fixed byte NrrSignature[0x100]; + + [FieldOffset(0x330)] + public ulong TitleIdMin; + + [FieldOffset(0x338)] + public uint NrrSize; + + [FieldOffset(0x340)] + public uint HashOffset; + + [FieldOffset(0x344)] + public uint HashCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrInfo.cs b/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrInfo.cs new file mode 100644 index 00000000..3636ce33 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ldr/Types/NrrInfo.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + class NrrInfo + { + public NrrHeader Header { get; private set; } + public List Hashes { get; private set; } + public long NrrAddress { get; private set; } + + public NrrInfo(long nrrAddress, NrrHeader header, List hashes) + { + NrrAddress = nrrAddress; + Header = header; + Hashes = hashes; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs b/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs index 019cd7d4..9fc46766 100644 --- a/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs +++ b/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Lm.LogService; + namespace Ryujinx.HLE.HOS.Services.Lm { [Service("lm")] diff --git a/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs b/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs deleted file mode 100644 index 4b297760..00000000 --- a/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Ryujinx.Common.Logging; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Lm -{ - class ILogger : IpcService - { - public ILogger() { } - - [Command(0)] - // Log(buffer) - public ResultCode Log(ServiceCtx context) - { - (long bufPos, long bufSize) = context.Request.GetBufferType0x21(); - byte[] logBuffer = context.Memory.ReadBytes(bufPos, bufSize); - - using (MemoryStream ms = new MemoryStream(logBuffer)) - { - BinaryReader reader = new BinaryReader(ms); - - long pid = reader.ReadInt64(); - long threadContext = reader.ReadInt64(); - short flags = reader.ReadInt16(); - byte level = reader.ReadByte(); - byte verbosity = reader.ReadByte(); - int payloadLength = reader.ReadInt32(); - - StringBuilder sb = new StringBuilder(); - - sb.AppendLine("Guest log:"); - - sb.AppendLine($" Log level: {(LmLogLevel)level}"); - - while (ms.Position < ms.Length) - { - byte type = reader.ReadByte(); - byte size = reader.ReadByte(); - - LmLogField field = (LmLogField)type; - - string fieldStr = string.Empty; - - if (field == LmLogField.Start) - { - reader.ReadBytes(size); - - continue; - } - else if (field == LmLogField.Stop) - { - break; - } - else if (field == LmLogField.Line) - { - fieldStr = $"{field}: {reader.ReadInt32()}"; - } - else if (field == LmLogField.DropCount) - { - fieldStr = $"{field}: {reader.ReadInt64()}"; - } - else if (field == LmLogField.Time) - { - fieldStr = $"{field}: {reader.ReadInt64()}s"; - } - else if (field < LmLogField.Count) - { - fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'"; - } - else - { - fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'"; - } - - sb.AppendLine(" " + fieldStr); - } - - string text = sb.ToString(); - - Logger.PrintGuest(LogClass.ServiceLm, text); - } - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs b/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs deleted file mode 100644 index 95474634..00000000 --- a/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Lm -{ - enum LmLogField - { - Start = 0, - Stop = 1, - Message = 2, - Line = 3, - Filename = 4, - Function = 5, - Module = 6, - Thread = 7, - DropCount = 8, - Time = 9, - ProgramName = 10, - Count - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs b/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs deleted file mode 100644 index 70554c42..00000000 --- a/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Lm -{ - enum LmLogLevel - { - Trace, - Info, - Warning, - Error, - Critical - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LogService/ILogger.cs b/Ryujinx.HLE/HOS/Services/Lm/LogService/ILogger.cs new file mode 100644 index 00000000..357a1332 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/LogService/ILogger.cs @@ -0,0 +1,86 @@ +using Ryujinx.Common.Logging; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Lm.LogService +{ + class ILogger : IpcService + { + public ILogger() { } + + [Command(0)] + // Log(buffer) + public ResultCode Log(ServiceCtx context) + { + (long bufPos, long bufSize) = context.Request.GetBufferType0x21(); + byte[] logBuffer = context.Memory.ReadBytes(bufPos, bufSize); + + using (MemoryStream ms = new MemoryStream(logBuffer)) + { + BinaryReader reader = new BinaryReader(ms); + + long pid = reader.ReadInt64(); + long threadContext = reader.ReadInt64(); + short flags = reader.ReadInt16(); + byte level = reader.ReadByte(); + byte verbosity = reader.ReadByte(); + int payloadLength = reader.ReadInt32(); + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("Guest log:"); + + sb.AppendLine($" Log level: {(LmLogLevel)level}"); + + while (ms.Position < ms.Length) + { + byte type = reader.ReadByte(); + byte size = reader.ReadByte(); + + LmLogField field = (LmLogField)type; + + string fieldStr = string.Empty; + + if (field == LmLogField.Start) + { + reader.ReadBytes(size); + + continue; + } + else if (field == LmLogField.Stop) + { + break; + } + else if (field == LmLogField.Line) + { + fieldStr = $"{field}: {reader.ReadInt32()}"; + } + else if (field == LmLogField.DropCount) + { + fieldStr = $"{field}: {reader.ReadInt64()}"; + } + else if (field == LmLogField.Time) + { + fieldStr = $"{field}: {reader.ReadInt64()}s"; + } + else if (field < LmLogField.Count) + { + fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'"; + } + else + { + fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'"; + } + + sb.AppendLine(" " + fieldStr); + } + + string text = sb.ToString(); + + Logger.PrintGuest(LogClass.ServiceLm, text); + } + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogField.cs b/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogField.cs new file mode 100644 index 00000000..3f93e167 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogField.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.HLE.HOS.Services.Lm.LogService +{ + enum LmLogField + { + Start = 0, + Stop = 1, + Message = 2, + Line = 3, + Filename = 4, + Function = 5, + Module = 6, + Thread = 7, + DropCount = 8, + Time = 9, + ProgramName = 10, + Count + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogLevel.cs b/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogLevel.cs new file mode 100644 index 00000000..ee1a8396 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/LogService/Types/LmLogLevel.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Lm.LogService +{ + enum LmLogLevel + { + Trace, + Info, + Warning, + Error, + Critical + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs deleted file mode 100644 index 1eb38d05..00000000 --- a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs +++ /dev/null @@ -1,254 +0,0 @@ -using LibHac.Fs.NcaUtils; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; -using System.Text; - -using static Ryujinx.HLE.Utilities.StringUtils; - -namespace Ryujinx.HLE.HOS.Services.Lr -{ - class ILocationResolver : IpcService - { - private StorageId _storageId; - - public ILocationResolver(StorageId storageId) - { - _storageId = storageId; - } - - [Command(0)] - // ResolveProgramPath() - public ResultCode ResolveProgramPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - if (ResolvePath(context, titleId, ContentType.Program)) - { - return ResultCode.Success; - } - else - { - return ResultCode.ProgramLocationEntryNotFound; - } - } - - [Command(1)] - // RedirectProgramPath() - public ResultCode RedirectProgramPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - RedirectPath(context, titleId, 0, ContentType.Program); - - return ResultCode.Success; - } - - [Command(2)] - // ResolveApplicationControlPath() - public ResultCode ResolveApplicationControlPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - if (ResolvePath(context, titleId, ContentType.Control)) - { - return ResultCode.Success; - } - else - { - return ResultCode.AccessDenied; - } - } - - [Command(3)] - // ResolveApplicationHtmlDocumentPath() - public ResultCode ResolveApplicationHtmlDocumentPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - if (ResolvePath(context, titleId, ContentType.Manual)) - { - return ResultCode.Success; - } - else - { - return ResultCode.AccessDenied; - } - } - - [Command(4)] - // ResolveDataPath() - public ResultCode ResolveDataPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData)) - { - return ResultCode.Success; - } - else - { - return ResultCode.AccessDenied; - } - } - - [Command(5)] - // RedirectApplicationControlPath() - public ResultCode RedirectApplicationControlPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - RedirectPath(context, titleId, 1, ContentType.Control); - - return ResultCode.Success; - } - - [Command(6)] - // RedirectApplicationHtmlDocumentPath() - public ResultCode RedirectApplicationHtmlDocumentPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - RedirectPath(context, titleId, 1, ContentType.Manual); - - return ResultCode.Success; - } - - [Command(7)] - // ResolveApplicationLegalInformationPath() - public ResultCode ResolveApplicationLegalInformationPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - if (ResolvePath(context, titleId, ContentType.Manual)) - { - return ResultCode.Success; - } - else - { - return ResultCode.AccessDenied; - } - } - - [Command(8)] - // RedirectApplicationLegalInformationPath() - public ResultCode RedirectApplicationLegalInformationPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - RedirectPath(context, titleId, 1, ContentType.Manual); - - return ResultCode.Success; - } - - [Command(9)] - // Refresh() - public ResultCode Refresh(ServiceCtx context) - { - context.Device.System.ContentManager.RefreshEntries(_storageId, 1); - - return ResultCode.Success; - } - - [Command(10)] - // SetProgramNcaPath2() - public ResultCode SetProgramNcaPath2(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - RedirectPath(context, titleId, 1, ContentType.Program); - - return ResultCode.Success; - } - - [Command(11)] - // ClearLocationResolver2() - public ResultCode ClearLocationResolver2(ServiceCtx context) - { - context.Device.System.ContentManager.RefreshEntries(_storageId, 1); - - return ResultCode.Success; - } - - [Command(12)] - // DeleteProgramNcaPath() - public ResultCode DeleteProgramNcaPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - DeleteContentPath(context, titleId, ContentType.Program); - - return ResultCode.Success; - } - - [Command(13)] - // DeleteControlNcaPath() - public ResultCode DeleteControlNcaPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - DeleteContentPath(context, titleId, ContentType.Control); - - return ResultCode.Success; - } - - [Command(14)] - // DeleteDocHtmlNcaPath() - public ResultCode DeleteDocHtmlNcaPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - DeleteContentPath(context, titleId, ContentType.Manual); - - return ResultCode.Success; - } - - [Command(15)] - // DeleteInfoHtmlNcaPath() - public ResultCode DeleteInfoHtmlNcaPath(ServiceCtx context) - { - long titleId = context.RequestData.ReadInt64(); - - DeleteContentPath(context, titleId, ContentType.Manual); - - return ResultCode.Success; - } - - private void RedirectPath(ServiceCtx context, long titleId, int flag, ContentType contentType) - { - string contentPath = ReadUtf8String(context); - LocationEntry newLocation = new LocationEntry(contentPath, flag, titleId, contentType); - - context.Device.System.ContentManager.RedirectLocation(newLocation, _storageId); - } - - private bool ResolvePath(ServiceCtx context, long titleId,ContentType contentType) - { - ContentManager contentManager = context.Device.System.ContentManager; - string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Program); - - if (!string.IsNullOrWhiteSpace(contentPath)) - { - long position = context.Request.RecvListBuff[0].Position; - long size = context.Request.RecvListBuff[0].Size; - - byte[] contentPathBuffer = Encoding.UTF8.GetBytes(contentPath); - - context.Memory.WriteBytes(position, contentPathBuffer); - } - else - { - return false; - } - - return true; - } - - private void DeleteContentPath(ServiceCtx context, long titleId, ContentType contentType) - { - ContentManager contentManager = context.Device.System.ContentManager; - string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Manual); - - contentManager.ClearEntry(titleId, ContentType.Manual, _storageId); - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs deleted file mode 100644 index 14ed0ca7..00000000 --- a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Ryujinx.HLE.FileSystem; - -namespace Ryujinx.HLE.HOS.Services.Lr -{ - [Service("lr")] - class ILocationResolverManager : IpcService - { - public ILocationResolverManager(ServiceCtx context) { } - - [Command(0)] - // OpenLocationResolver() - public ResultCode OpenLocationResolver(ServiceCtx context) - { - StorageId storageId = (StorageId)context.RequestData.ReadByte(); - - MakeObject(context, new ILocationResolver(storageId)); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lr/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Lr/ResultCode.cs deleted file mode 100644 index 10c42cd6..00000000 --- a/Ryujinx.HLE/HOS/Services/Lr/ResultCode.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Lr -{ - enum ResultCode - { - ModuleId = 8, - ErrorCodeShift = 9, - - Success = 0, - - ProgramLocationEntryNotFound = (2 << ErrorCodeShift) | ModuleId, - AccessDenied = (5 << ErrorCodeShift) | ModuleId - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Mig/IService.cs b/Ryujinx.HLE/HOS/Services/Mig/IService.cs new file mode 100644 index 00000000..2f6eb99e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Mig/IService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Mig +{ + [Service("mig:usr")] // 4.0.0+ + class IService : IpcService + { + public IService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs b/Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs deleted file mode 100644 index 5bfbe4db..00000000 --- a/Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Ncm -{ - class IContentStorage : IpcService - { - public IContentStorage() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs new file mode 100644 index 00000000..44b8272b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs @@ -0,0 +1,22 @@ +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager; + +namespace Ryujinx.HLE.HOS.Services.Ncm.Lr +{ + [Service("lr")] + class ILocationResolverManager : IpcService + { + public ILocationResolverManager(ServiceCtx context) { } + + [Command(0)] + // OpenLocationResolver() + public ResultCode OpenLocationResolver(ServiceCtx context) + { + StorageId storageId = (StorageId)context.RequestData.ReadByte(); + + MakeObject(context, new ILocationResolver(storageId)); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs b/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs new file mode 100644 index 00000000..d77bac73 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs @@ -0,0 +1,254 @@ +using LibHac.Fs.NcaUtils; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.FileSystem.Content; +using System.Text; + +using static Ryujinx.HLE.Utilities.StringUtils; + +namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager +{ + class ILocationResolver : IpcService + { + private StorageId _storageId; + + public ILocationResolver(StorageId storageId) + { + _storageId = storageId; + } + + [Command(0)] + // ResolveProgramPath() + public ResultCode ResolveProgramPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + if (ResolvePath(context, titleId, ContentType.Program)) + { + return ResultCode.Success; + } + else + { + return ResultCode.ProgramLocationEntryNotFound; + } + } + + [Command(1)] + // RedirectProgramPath() + public ResultCode RedirectProgramPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + RedirectPath(context, titleId, 0, ContentType.Program); + + return ResultCode.Success; + } + + [Command(2)] + // ResolveApplicationControlPath() + public ResultCode ResolveApplicationControlPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + if (ResolvePath(context, titleId, ContentType.Control)) + { + return ResultCode.Success; + } + else + { + return ResultCode.AccessDenied; + } + } + + [Command(3)] + // ResolveApplicationHtmlDocumentPath() + public ResultCode ResolveApplicationHtmlDocumentPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + if (ResolvePath(context, titleId, ContentType.Manual)) + { + return ResultCode.Success; + } + else + { + return ResultCode.AccessDenied; + } + } + + [Command(4)] + // ResolveDataPath() + public ResultCode ResolveDataPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData)) + { + return ResultCode.Success; + } + else + { + return ResultCode.AccessDenied; + } + } + + [Command(5)] + // RedirectApplicationControlPath() + public ResultCode RedirectApplicationControlPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + RedirectPath(context, titleId, 1, ContentType.Control); + + return ResultCode.Success; + } + + [Command(6)] + // RedirectApplicationHtmlDocumentPath() + public ResultCode RedirectApplicationHtmlDocumentPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + RedirectPath(context, titleId, 1, ContentType.Manual); + + return ResultCode.Success; + } + + [Command(7)] + // ResolveApplicationLegalInformationPath() + public ResultCode ResolveApplicationLegalInformationPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + if (ResolvePath(context, titleId, ContentType.Manual)) + { + return ResultCode.Success; + } + else + { + return ResultCode.AccessDenied; + } + } + + [Command(8)] + // RedirectApplicationLegalInformationPath() + public ResultCode RedirectApplicationLegalInformationPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + RedirectPath(context, titleId, 1, ContentType.Manual); + + return ResultCode.Success; + } + + [Command(9)] + // Refresh() + public ResultCode Refresh(ServiceCtx context) + { + context.Device.System.ContentManager.RefreshEntries(_storageId, 1); + + return ResultCode.Success; + } + + [Command(10)] + // SetProgramNcaPath2() + public ResultCode SetProgramNcaPath2(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + RedirectPath(context, titleId, 1, ContentType.Program); + + return ResultCode.Success; + } + + [Command(11)] + // ClearLocationResolver2() + public ResultCode ClearLocationResolver2(ServiceCtx context) + { + context.Device.System.ContentManager.RefreshEntries(_storageId, 1); + + return ResultCode.Success; + } + + [Command(12)] + // DeleteProgramNcaPath() + public ResultCode DeleteProgramNcaPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + DeleteContentPath(context, titleId, ContentType.Program); + + return ResultCode.Success; + } + + [Command(13)] + // DeleteControlNcaPath() + public ResultCode DeleteControlNcaPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + DeleteContentPath(context, titleId, ContentType.Control); + + return ResultCode.Success; + } + + [Command(14)] + // DeleteDocHtmlNcaPath() + public ResultCode DeleteDocHtmlNcaPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + DeleteContentPath(context, titleId, ContentType.Manual); + + return ResultCode.Success; + } + + [Command(15)] + // DeleteInfoHtmlNcaPath() + public ResultCode DeleteInfoHtmlNcaPath(ServiceCtx context) + { + long titleId = context.RequestData.ReadInt64(); + + DeleteContentPath(context, titleId, ContentType.Manual); + + return ResultCode.Success; + } + + private void RedirectPath(ServiceCtx context, long titleId, int flag, ContentType contentType) + { + string contentPath = ReadUtf8String(context); + LocationEntry newLocation = new LocationEntry(contentPath, flag, titleId, contentType); + + context.Device.System.ContentManager.RedirectLocation(newLocation, _storageId); + } + + private bool ResolvePath(ServiceCtx context, long titleId,ContentType contentType) + { + ContentManager contentManager = context.Device.System.ContentManager; + string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Program); + + if (!string.IsNullOrWhiteSpace(contentPath)) + { + long position = context.Request.RecvListBuff[0].Position; + long size = context.Request.RecvListBuff[0].Size; + + byte[] contentPathBuffer = Encoding.UTF8.GetBytes(contentPath); + + context.Memory.WriteBytes(position, contentPathBuffer); + } + else + { + return false; + } + + return true; + } + + private void DeleteContentPath(ServiceCtx context, long titleId, ContentType contentType) + { + ContentManager contentManager = context.Device.System.ContentManager; + string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Manual); + + contentManager.ClearEntry(titleId, ContentType.Manual, _storageId); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Ncm/Lr/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ResultCode.cs new file mode 100644 index 00000000..5ff7e466 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ResultCode.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Ncm.Lr +{ + enum ResultCode + { + ModuleId = 8, + ErrorCodeShift = 9, + + Success = 0, + + ProgramLocationEntryNotFound = (2 << ErrorCodeShift) | ModuleId, + AccessDenied = (5 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/News/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/News/IServiceCreator.cs new file mode 100644 index 00000000..7ea89b20 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/News/IServiceCreator.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.News +{ + [Service("news:a")] + [Service("news:c")] + [Service("news:m")] + [Service("news:p")] + [Service("news:v")] + class IServiceCreator : IpcService + { + public IServiceCreator(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/IAmManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/IAmManager.cs new file mode 100644 index 00000000..33932568 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/IAmManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc +{ + [Service("nfc:am")] + class IAmManager : IpcService + { + public IAmManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/ISystemManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/ISystemManager.cs new file mode 100644 index 00000000..0bab0b79 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/ISystemManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc +{ + [Service("nfc:sys")] + class ISystemManager : IpcService + { + public ISystemManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/IUserManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/IUserManager.cs new file mode 100644 index 00000000..048adf8c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/IUserManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc +{ + [Service("nfc:user")] + class IUserManager : IpcService + { + public IUserManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Mifare/IUserManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/Mifare/IUserManager.cs new file mode 100644 index 00000000..cc3cd3aa --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Mifare/IUserManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc.Mifare +{ + [Service("nfc:mf:u")] + class IUserManager : IpcService + { + public IUserManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs deleted file mode 100644 index 3c49ee51..00000000 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Hid; -using Ryujinx.HLE.Input; - -namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp -{ - class Device - { - public KEvent ActivateEvent; - public int ActivateEventHandle; - - public KEvent DeactivateEvent; - public int DeactivateEventHandle; - - public DeviceState State = DeviceState.Unavailable; - - public ControllerId Handle; - public NpadIdType NpadIdType; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs deleted file mode 100644 index 09cff5f8..00000000 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp -{ - enum DeviceState - { - Initialized = 0, - SearchingForTag = 1, - TagFound = 2, - TagRemoved = 3, - TagMounted = 4, - Unavailable = 5, - Finalized = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IDebugManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IDebugManager.cs new file mode 100644 index 00000000..c5da8da9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IDebugManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp +{ + [Service("nfp:dbg")] + class IAmManager : IpcService + { + public IAmManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/ISystemManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/ISystemManager.cs new file mode 100644 index 00000000..78ea4896 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/ISystemManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp +{ + [Service("nfp:sys")] + class ISystemManager : IpcService + { + public ISystemManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs deleted file mode 100644 index c8a7ae4b..00000000 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs +++ /dev/null @@ -1,336 +0,0 @@ -using Ryujinx.HLE.Exceptions; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Hid; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp -{ - class IUser : IpcService - { - private State _state = State.NonInitialized; - - private KEvent _availabilityChangeEvent; - private int _availabilityChangeEventHandle = 0; - - private List _devices = new List(); - - public IUser() { } - - [Command(0)] - // Initialize(u64, u64, pid, buffer) - public ResultCode Initialize(ServiceCtx context) - { - long appletResourceUserId = context.RequestData.ReadInt64(); - long mcuVersionData = context.RequestData.ReadInt64(); - - long inputPosition = context.Request.SendBuff[0].Position; - long inputSize = context.Request.SendBuff[0].Size; - - byte[] unknownBuffer = context.Memory.ReadBytes(inputPosition, inputSize); - - // NOTE: appletResourceUserId, mcuVersionData and the buffer are stored inside an internal struct. - // The buffer seems to contains entries with a size of 0x40 bytes each. - // Sadly, this internal struct doesn't seems to be used in retail. - - // TODO: Add an instance of nn::nfc::server::Manager when it will be implemented. - // Add an instance of nn::nfc::server::SaveData when it will be implemented. - - // TODO: When we will be able to add multiple controllers add one entry by controller here. - Device device1 = new Device - { - NpadIdType = NpadIdType.Player1, - Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1), - State = DeviceState.Initialized - }; - - _devices.Add(device1); - - _state = State.Initialized; - - return ResultCode.Success; - } - - [Command(1)] - // Finalize() - public ResultCode Finalize(ServiceCtx context) - { - // TODO: Call StopDetection() and Unmount() when they will be implemented. - // Remove the instance of nn::nfc::server::Manager when it will be implemented. - // Remove the instance of nn::nfc::server::SaveData when it will be implemented. - - _devices.Clear(); - - _state = State.NonInitialized; - - return ResultCode.Success; - } - - [Command(2)] - // ListDevices() -> (u32, buffer) - public ResultCode ListDevices(ServiceCtx context) - { - if (context.Request.RecvListBuff.Count == 0) - { - return ResultCode.DevicesBufferIsNull; - } - - long outputPosition = context.Request.RecvListBuff[0].Position; - long outputSize = context.Request.RecvListBuff[0].Size; - - if (_devices.Count == 0) - { - return ResultCode.DeviceNotFound; - } - - for (int i = 0; i < _devices.Count; i++) - { - context.Memory.WriteUInt32(outputPosition + (i * sizeof(long)), (uint)_devices[i].Handle); - } - - context.ResponseData.Write(_devices.Count); - - return ResultCode.Success; - } - - [Command(3)] - // StartDetection(bytes<8, 4>) - public ResultCode StartDetection(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(4)] - // StopDetection(bytes<8, 4>) - public ResultCode StopDetection(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(5)] - // Mount(bytes<8, 4>, u32, u32) - public ResultCode Mount(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(6)] - // Unmount(bytes<8, 4>) - public ResultCode Unmount(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(7)] - // OpenApplicationArea(bytes<8, 4>, u32) - public ResultCode OpenApplicationArea(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(8)] - // GetApplicationArea(bytes<8, 4>) -> (u32, buffer) - public ResultCode GetApplicationArea(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(9)] - // SetApplicationArea(bytes<8, 4>, buffer) - public ResultCode SetApplicationArea(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(10)] - // Flush(bytes<8, 4>) - public ResultCode Flush(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(11)] - // Restore(bytes<8, 4>) - public ResultCode Restore(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(12)] - // CreateApplicationArea(bytes<8, 4>, u32, buffer) - public ResultCode CreateApplicationArea(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(13)] - // GetTagInfo(bytes<8, 4>) -> buffer, 0x1a> - public ResultCode GetTagInfo(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(14)] - // GetRegisterInfo(bytes<8, 4>) -> buffer, 0x1a> - public ResultCode GetRegisterInfo(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(15)] - // GetCommonInfo(bytes<8, 4>) -> buffer, 0x1a> - public ResultCode GetCommonInfo(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(16)] - // GetModelInfo(bytes<8, 4>) -> buffer, 0x1a> - public ResultCode GetModelInfo(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(17)] - // AttachActivateEvent(bytes<8, 4>) -> handle - public ResultCode AttachActivateEvent(ServiceCtx context) - { - uint deviceHandle = context.RequestData.ReadUInt32(); - - for (int i = 0; i < _devices.Count; i++) - { - if ((uint)_devices[i].Handle == deviceHandle) - { - if (_devices[i].ActivateEventHandle == 0) - { - _devices[i].ActivateEvent = new KEvent(context.Device.System); - - if (context.Process.HandleTable.GenerateHandle(_devices[i].ActivateEvent.ReadableEvent, out _devices[i].ActivateEventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].ActivateEventHandle); - - return ResultCode.Success; - } - } - - return ResultCode.DeviceNotFound; - } - - [Command(18)] - // AttachDeactivateEvent(bytes<8, 4>) -> handle - public ResultCode AttachDeactivateEvent(ServiceCtx context) - { - uint deviceHandle = context.RequestData.ReadUInt32(); - - for (int i = 0; i < _devices.Count; i++) - { - if ((uint)_devices[i].Handle == deviceHandle) - { - if (_devices[i].DeactivateEventHandle == 0) - { - _devices[i].DeactivateEvent = new KEvent(context.Device.System); - - if (context.Process.HandleTable.GenerateHandle(_devices[i].DeactivateEvent.ReadableEvent, out _devices[i].DeactivateEventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].DeactivateEventHandle); - - return ResultCode.Success; - } - } - - return ResultCode.DeviceNotFound; - } - - [Command(19)] - // GetState() -> u32 - public ResultCode GetState(ServiceCtx context) - { - context.ResponseData.Write((int)_state); - - return ResultCode.Success; - } - - [Command(20)] - // GetDeviceState(bytes<8, 4>) -> u32 - public ResultCode GetDeviceState(ServiceCtx context) - { - uint deviceHandle = context.RequestData.ReadUInt32(); - - for (int i = 0; i < _devices.Count; i++) - { - if ((uint)_devices[i].Handle == deviceHandle) - { - context.ResponseData.Write((uint)_devices[i].State); - - return ResultCode.Success; - } - } - - context.ResponseData.Write((uint)DeviceState.Unavailable); - - return ResultCode.DeviceNotFound; - } - - [Command(21)] - // GetNpadId(bytes<8, 4>) -> u32 - public ResultCode GetNpadId(ServiceCtx context) - { - uint deviceHandle = context.RequestData.ReadUInt32(); - - for (int i = 0; i < _devices.Count; i++) - { - if ((uint)_devices[i].Handle == deviceHandle) - { - context.ResponseData.Write((uint)HidUtils.GetNpadIdTypeFromIndex(_devices[i].Handle)); - - return ResultCode.Success; - } - } - - return ResultCode.DeviceNotFound; - } - - [Command(22)] - // GetApplicationAreaSize(bytes<8, 4>) -> u32 - public ResultCode GetApplicationAreaSize(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(23)] // 3.0.0+ - // AttachAvailabilityChangeEvent() -> handle - public ResultCode AttachAvailabilityChangeEvent(ServiceCtx context) - { - if (_availabilityChangeEventHandle == 0) - { - _availabilityChangeEvent = new KEvent(context.Device.System); - - if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out _availabilityChangeEventHandle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_availabilityChangeEventHandle); - - return ResultCode.Success; - } - - [Command(24)] // 3.0.0+ - // RecreateApplicationArea(bytes<8, 4>, u32, buffer) - public ResultCode RecreateApplicationArea(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs deleted file mode 100644 index 166e5d7e..00000000 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp -{ - enum State - { - NonInitialized = 0, - Initialized = 1 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs new file mode 100644 index 00000000..d26b4eb9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs @@ -0,0 +1,338 @@ +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.HOS.Services.Hid.HidServer; +using Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp +{ + class IUser : IpcService + { + private State _state = State.NonInitialized; + + private KEvent _availabilityChangeEvent; + private int _availabilityChangeEventHandle = 0; + + private List _devices = new List(); + + public IUser() { } + + [Command(0)] + // Initialize(u64, u64, pid, buffer) + public ResultCode Initialize(ServiceCtx context) + { + long appletResourceUserId = context.RequestData.ReadInt64(); + long mcuVersionData = context.RequestData.ReadInt64(); + + long inputPosition = context.Request.SendBuff[0].Position; + long inputSize = context.Request.SendBuff[0].Size; + + byte[] unknownBuffer = context.Memory.ReadBytes(inputPosition, inputSize); + + // NOTE: appletResourceUserId, mcuVersionData and the buffer are stored inside an internal struct. + // The buffer seems to contains entries with a size of 0x40 bytes each. + // Sadly, this internal struct doesn't seems to be used in retail. + + // TODO: Add an instance of nn::nfc::server::Manager when it will be implemented. + // Add an instance of nn::nfc::server::SaveData when it will be implemented. + + // TODO: When we will be able to add multiple controllers add one entry by controller here. + Device device1 = new Device + { + NpadIdType = HidNpadIdType.Player1, + Handle = HidUtils.GetIndexFromNpadIdType(HidNpadIdType.Player1), + State = DeviceState.Initialized + }; + + _devices.Add(device1); + + _state = State.Initialized; + + return ResultCode.Success; + } + + [Command(1)] + // Finalize() + public ResultCode Finalize(ServiceCtx context) + { + // TODO: Call StopDetection() and Unmount() when they will be implemented. + // Remove the instance of nn::nfc::server::Manager when it will be implemented. + // Remove the instance of nn::nfc::server::SaveData when it will be implemented. + + _devices.Clear(); + + _state = State.NonInitialized; + + return ResultCode.Success; + } + + [Command(2)] + // ListDevices() -> (u32, buffer) + public ResultCode ListDevices(ServiceCtx context) + { + if (context.Request.RecvListBuff.Count == 0) + { + return ResultCode.DevicesBufferIsNull; + } + + long outputPosition = context.Request.RecvListBuff[0].Position; + long outputSize = context.Request.RecvListBuff[0].Size; + + if (_devices.Count == 0) + { + return ResultCode.DeviceNotFound; + } + + for (int i = 0; i < _devices.Count; i++) + { + context.Memory.WriteUInt32(outputPosition + (i * sizeof(long)), (uint)_devices[i].Handle); + } + + context.ResponseData.Write(_devices.Count); + + return ResultCode.Success; + } + + [Command(3)] + // StartDetection(bytes<8, 4>) + public ResultCode StartDetection(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(4)] + // StopDetection(bytes<8, 4>) + public ResultCode StopDetection(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(5)] + // Mount(bytes<8, 4>, u32, u32) + public ResultCode Mount(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(6)] + // Unmount(bytes<8, 4>) + public ResultCode Unmount(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(7)] + // OpenApplicationArea(bytes<8, 4>, u32) + public ResultCode OpenApplicationArea(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(8)] + // GetApplicationArea(bytes<8, 4>) -> (u32, buffer) + public ResultCode GetApplicationArea(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(9)] + // SetApplicationArea(bytes<8, 4>, buffer) + public ResultCode SetApplicationArea(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(10)] + // Flush(bytes<8, 4>) + public ResultCode Flush(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(11)] + // Restore(bytes<8, 4>) + public ResultCode Restore(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(12)] + // CreateApplicationArea(bytes<8, 4>, u32, buffer) + public ResultCode CreateApplicationArea(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(13)] + // GetTagInfo(bytes<8, 4>) -> buffer, 0x1a> + public ResultCode GetTagInfo(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(14)] + // GetRegisterInfo(bytes<8, 4>) -> buffer, 0x1a> + public ResultCode GetRegisterInfo(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(15)] + // GetCommonInfo(bytes<8, 4>) -> buffer, 0x1a> + public ResultCode GetCommonInfo(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(16)] + // GetModelInfo(bytes<8, 4>) -> buffer, 0x1a> + public ResultCode GetModelInfo(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(17)] + // AttachActivateEvent(bytes<8, 4>) -> handle + public ResultCode AttachActivateEvent(ServiceCtx context) + { + uint deviceHandle = context.RequestData.ReadUInt32(); + + for (int i = 0; i < _devices.Count; i++) + { + if ((uint)_devices[i].Handle == deviceHandle) + { + if (_devices[i].ActivateEventHandle == 0) + { + _devices[i].ActivateEvent = new KEvent(context.Device.System); + + if (context.Process.HandleTable.GenerateHandle(_devices[i].ActivateEvent.ReadableEvent, out _devices[i].ActivateEventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].ActivateEventHandle); + + return ResultCode.Success; + } + } + + return ResultCode.DeviceNotFound; + } + + [Command(18)] + // AttachDeactivateEvent(bytes<8, 4>) -> handle + public ResultCode AttachDeactivateEvent(ServiceCtx context) + { + uint deviceHandle = context.RequestData.ReadUInt32(); + + for (int i = 0; i < _devices.Count; i++) + { + if ((uint)_devices[i].Handle == deviceHandle) + { + if (_devices[i].DeactivateEventHandle == 0) + { + _devices[i].DeactivateEvent = new KEvent(context.Device.System); + + if (context.Process.HandleTable.GenerateHandle(_devices[i].DeactivateEvent.ReadableEvent, out _devices[i].DeactivateEventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].DeactivateEventHandle); + + return ResultCode.Success; + } + } + + return ResultCode.DeviceNotFound; + } + + [Command(19)] + // GetState() -> u32 + public ResultCode GetState(ServiceCtx context) + { + context.ResponseData.Write((int)_state); + + return ResultCode.Success; + } + + [Command(20)] + // GetDeviceState(bytes<8, 4>) -> u32 + public ResultCode GetDeviceState(ServiceCtx context) + { + uint deviceHandle = context.RequestData.ReadUInt32(); + + for (int i = 0; i < _devices.Count; i++) + { + if ((uint)_devices[i].Handle == deviceHandle) + { + context.ResponseData.Write((uint)_devices[i].State); + + return ResultCode.Success; + } + } + + context.ResponseData.Write((uint)DeviceState.Unavailable); + + return ResultCode.DeviceNotFound; + } + + [Command(21)] + // GetNpadId(bytes<8, 4>) -> u32 + public ResultCode GetNpadId(ServiceCtx context) + { + uint deviceHandle = context.RequestData.ReadUInt32(); + + for (int i = 0; i < _devices.Count; i++) + { + if ((uint)_devices[i].Handle == deviceHandle) + { + context.ResponseData.Write((uint)HidUtils.GetNpadIdTypeFromIndex(_devices[i].Handle)); + + return ResultCode.Success; + } + } + + return ResultCode.DeviceNotFound; + } + + [Command(22)] + // GetApplicationAreaSize(bytes<8, 4>) -> u32 + public ResultCode GetApplicationAreaSize(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(23)] // 3.0.0+ + // AttachAvailabilityChangeEvent() -> handle + public ResultCode AttachAvailabilityChangeEvent(ServiceCtx context) + { + if (_availabilityChangeEventHandle == 0) + { + _availabilityChangeEvent = new KEvent(context.Device.System); + + if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out _availabilityChangeEventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_availabilityChangeEventHandle); + + return ResultCode.Success; + } + + [Command(24)] // 3.0.0+ + // RecreateApplicationArea(bytes<8, 4>, u32, buffer) + public ResultCode RecreateApplicationArea(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs new file mode 100644 index 00000000..40e7c880 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.Input; + +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager +{ + class Device + { + public KEvent ActivateEvent; + public int ActivateEventHandle; + + public KEvent DeactivateEvent; + public int DeactivateEventHandle; + + public DeviceState State = DeviceState.Unavailable; + + public ControllerId Handle; + public HidNpadIdType NpadIdType; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/DeviceState.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/DeviceState.cs new file mode 100644 index 00000000..7e373494 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/DeviceState.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager +{ + enum DeviceState + { + Initialized = 0, + SearchingForTag = 1, + TagFound = 2, + TagRemoved = 3, + TagMounted = 4, + Unavailable = 5, + Finalized = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/State.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/State.cs new file mode 100644 index 00000000..8d141f0b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/State.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager +{ + enum State + { + NonInitialized = 0, + Initialized = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs b/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs new file mode 100644 index 00000000..2baec585 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ngct/IUnknown1.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Ngct +{ + [Service("ngct:s")] // 9.0.0+ + [Service("ngct:u")] // 9.0.0+ + class IUnknown1 : IpcService + { + public IUnknown1(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceDetail.cs b/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceDetail.cs deleted file mode 100644 index 3be5fbeb..00000000 --- a/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceDetail.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nifm -{ - class GeneralServiceDetail - { - public int ClientId; - public bool IsAnyInternetRequestAccepted; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceManager.cs b/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceManager.cs deleted file mode 100644 index 1b49229e..00000000 --- a/Ryujinx.HLE/HOS/Services/Nifm/GeneralServiceManager.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.HLE.HOS.Services.Nifm -{ - static class GeneralServiceManager - { - private static List _generalServices = new List(); - - public static int Count - { - get => _generalServices.Count; - } - - public static void Add(GeneralServiceDetail generalServiceDetail) - { - _generalServices.Add(generalServiceDetail); - } - - public static void Remove(int index) - { - _generalServices.RemoveAt(index); - } - - public static GeneralServiceDetail Get(int clientId) - { - return _generalServices.First(item => item.ClientId == clientId); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs b/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs deleted file mode 100644 index a47e7300..00000000 --- a/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Ryujinx.Common.Logging; -using System; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; - -namespace Ryujinx.HLE.HOS.Services.Nifm -{ - class IGeneralService : IpcService, IDisposable - { - private GeneralServiceDetail _generalServiceDetail; - - public IGeneralService() - { - _generalServiceDetail = new GeneralServiceDetail - { - ClientId = GeneralServiceManager.Count, - IsAnyInternetRequestAccepted = true // NOTE: Why not accept any internet request? - }; - - GeneralServiceManager.Add(_generalServiceDetail); - } - - [Command(1)] - // GetClientId() -> buffer - public ResultCode GetClientId(ServiceCtx context) - { - long position = context.Request.RecvListBuff[0].Position; - long size = context.Request.RecvListBuff[0].Size; - - context.Memory.WriteInt32(position, _generalServiceDetail.ClientId); - - return ResultCode.Success; - } - - [Command(4)] - // CreateRequest(u32 version) -> object - public ResultCode CreateRequest(ServiceCtx context) - { - uint version = context.RequestData.ReadUInt32(); - - MakeObject(context, new IRequest(context.Device.System, version)); - - // Doesn't occur in our case. - // return ResultCode.ObjectIsNull; - - Logger.PrintStub(LogClass.ServiceNifm, new { version }); - - return ResultCode.Success; - } - - [Command(12)] - // GetCurrentIpAddress() -> nn::nifm::IpV4Address - public ResultCode GetCurrentIpAddress(ServiceCtx context) - { - if (!NetworkInterface.GetIsNetworkAvailable()) - { - return ResultCode.NoInternetConnection; - } - - IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); - - IPAddress address = host.AddressList.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork); - - context.ResponseData.Write(BitConverter.ToUInt32(address.GetAddressBytes())); - - Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{address}\"."); - - return ResultCode.Success; - } - - [Command(21)] - // IsAnyInternetRequestAccepted(buffer) -> bool - public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context) - { - long position = context.Request.PtrBuff[0].Position; - long size = context.Request.PtrBuff[0].Size; - - int clientId = context.Memory.ReadInt32(position); - - context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted); - - return ResultCode.Success; - } - - public void Dispose() - { - GeneralServiceManager.Remove(_generalServiceDetail.ClientId); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs deleted file mode 100644 index b2884f91..00000000 --- a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using System; - -namespace Ryujinx.HLE.HOS.Services.Nifm -{ - class IRequest : IpcService - { - private KEvent _event0; - private KEvent _event1; - - private uint _version; - - public IRequest(Horizon system, uint version) - { - _event0 = new KEvent(system); - _event1 = new KEvent(system); - - _version = version; - } - - [Command(0)] - // GetRequestState() -> u32 - public ResultCode GetRequestState(ServiceCtx context) - { - context.ResponseData.Write(1); - - Logger.PrintStub(LogClass.ServiceNifm); - - return ResultCode.Success; - } - - [Command(1)] - // GetResult() - public ResultCode GetResult(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceNifm); - - return ResultCode.Success; - } - - [Command(2)] - // GetSystemEventReadableHandles() -> (handle, handle) - public ResultCode GetSystemEventReadableHandles(ServiceCtx context) - { - if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1); - - return ResultCode.Success; - } - - [Command(3)] - // Cancel() - public ResultCode Cancel(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceNifm); - - return ResultCode.Success; - } - - [Command(4)] - // Submit() - public ResultCode Submit(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceNifm); - - return ResultCode.Success; - } - - [Command(11)] - // SetConnectionConfirmationOption(i8) - public ResultCode SetConnectionConfirmationOption(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceNifm); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs index eaecc3d3..0cf6a43c 100644 --- a/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Nifm.StaticService; + namespace Ryujinx.HLE.HOS.Services.Nifm { [Service("nifm:a")] // Max sessions: 2 diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs new file mode 100644 index 00000000..bbb218bb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/GeneralServiceManager.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService +{ + static class GeneralServiceManager + { + private static List _generalServices = new List(); + + public static int Count + { + get => _generalServices.Count; + } + + public static void Add(GeneralServiceDetail generalServiceDetail) + { + _generalServices.Add(generalServiceDetail); + } + + public static void Remove(int index) + { + _generalServices.RemoveAt(index); + } + + public static GeneralServiceDetail Get(int clientId) + { + return _generalServices.First(item => item.ClientId == clientId); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs new file mode 100644 index 00000000..3cf55345 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/GeneralService/Types/GeneralServiceDetail.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService +{ + class GeneralServiceDetail + { + public int ClientId; + public bool IsAnyInternetRequestAccepted; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs new file mode 100644 index 00000000..4a07b298 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs @@ -0,0 +1,93 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService; +using System; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; + +namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService +{ + class IGeneralService : IpcService, IDisposable + { + private GeneralServiceDetail _generalServiceDetail; + + public IGeneralService() + { + _generalServiceDetail = new GeneralServiceDetail + { + ClientId = GeneralServiceManager.Count, + IsAnyInternetRequestAccepted = true // NOTE: Why not accept any internet request? + }; + + GeneralServiceManager.Add(_generalServiceDetail); + } + + [Command(1)] + // GetClientId() -> buffer + public ResultCode GetClientId(ServiceCtx context) + { + long position = context.Request.RecvListBuff[0].Position; + long size = context.Request.RecvListBuff[0].Size; + + context.Memory.WriteInt32(position, _generalServiceDetail.ClientId); + + return ResultCode.Success; + } + + [Command(4)] + // CreateRequest(u32 version) -> object + public ResultCode CreateRequest(ServiceCtx context) + { + uint version = context.RequestData.ReadUInt32(); + + MakeObject(context, new IRequest(context.Device.System, version)); + + // Doesn't occur in our case. + // return ResultCode.ObjectIsNull; + + Logger.PrintStub(LogClass.ServiceNifm, new { version }); + + return ResultCode.Success; + } + + [Command(12)] + // GetCurrentIpAddress() -> nn::nifm::IpV4Address + public ResultCode GetCurrentIpAddress(ServiceCtx context) + { + if (!NetworkInterface.GetIsNetworkAvailable()) + { + return ResultCode.NoInternetConnection; + } + + IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); + + IPAddress address = host.AddressList.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork); + + context.ResponseData.Write(BitConverter.ToUInt32(address.GetAddressBytes())); + + Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{address}\"."); + + return ResultCode.Success; + } + + [Command(21)] + // IsAnyInternetRequestAccepted(buffer) -> bool + public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context) + { + long position = context.Request.PtrBuff[0].Position; + long size = context.Request.PtrBuff[0].Size; + + int clientId = context.Memory.ReadInt32(position); + + context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted); + + return ResultCode.Success; + } + + public void Dispose() + { + GeneralServiceManager.Remove(_generalServiceDetail.ClientId); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs new file mode 100644 index 00000000..c878c2d6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs @@ -0,0 +1,90 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using System; + +namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService +{ + class IRequest : IpcService + { + private KEvent _event0; + private KEvent _event1; + + private uint _version; + + public IRequest(Horizon system, uint version) + { + _event0 = new KEvent(system); + _event1 = new KEvent(system); + + _version = version; + } + + [Command(0)] + // GetRequestState() -> u32 + public ResultCode GetRequestState(ServiceCtx context) + { + context.ResponseData.Write(1); + + Logger.PrintStub(LogClass.ServiceNifm); + + return ResultCode.Success; + } + + [Command(1)] + // GetResult() + public ResultCode GetResult(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceNifm); + + return ResultCode.Success; + } + + [Command(2)] + // GetSystemEventReadableHandles() -> (handle, handle) + public ResultCode GetSystemEventReadableHandles(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1); + + return ResultCode.Success; + } + + [Command(3)] + // Cancel() + public ResultCode Cancel(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceNifm); + + return ResultCode.Success; + } + + [Command(4)] + // Submit() + public ResultCode Submit(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceNifm); + + return ResultCode.Success; + } + + [Command(11)] + // SetConnectionConfirmationOption(i8) + public ResultCode SetConnectionConfirmationOption(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceNifm); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nim/INetworkInstallManager.cs b/Ryujinx.HLE/HOS/Services/Nim/INetworkInstallManager.cs new file mode 100644 index 00000000..ad79ca0d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nim/INetworkInstallManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nim +{ + [Service("nim")] + class INetworkInstallManager : IpcService + { + public INetworkInstallManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs new file mode 100644 index 00000000..9be84393 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nim +{ + [Service("nim:eca")] // 5.0.0+ + class IShopServiceAccessServerInterface : IpcService + { + public IShopServiceAccessServerInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessSystemInterface.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessSystemInterface.cs new file mode 100644 index 00000000..ab7bcaca --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessSystemInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ldr +{ + [Service("nim:ecas")] // 7.0.0+ + class IShopServiceAccessSystemInterface : IpcService + { + public IShopServiceAccessSystemInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceManager.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceManager.cs new file mode 100644 index 00000000..2420615a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nim +{ + [Service("nim:shp")] + class IShopServiceManager : IpcService + { + public IShopServiceManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nim/Ntc/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Nim/Ntc/IStaticService.cs new file mode 100644 index 00000000..f5a3bc7b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nim/Ntc/IStaticService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nim.Ntc +{ + [Service("ntc")] + class IStaticService : IpcService + { + public IStaticService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForApplication.cs b/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForApplication.cs new file mode 100644 index 00000000..c4a35b29 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForApplication.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Notification +{ + [Service("notif:a")] // 9.0.0+ + class INotificationServicesForApplication : IpcService + { + public INotificationServicesForApplication(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForSystem.cs b/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForSystem.cs new file mode 100644 index 00000000..0939dff6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Notification/INotificationServicesForSystem.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Notification +{ + [Service("notif:s")] // 9.0.0+ + class INotificationServicesForSystem : IpcService + { + public INotificationServicesForSystem(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Npns/INpnsSystem.cs b/Ryujinx.HLE/HOS/Services/Npns/INpnsSystem.cs new file mode 100644 index 00000000..fd8ccfb5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Npns/INpnsSystem.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Npns +{ + [Service("npns:s")] + class INpnsSystem : IpcService + { + public INpnsSystem(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Npns/INpnsUser.cs b/Ryujinx.HLE/HOS/Services/Npns/INpnsUser.cs new file mode 100644 index 00000000..68e76938 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Npns/INpnsUser.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Npns +{ + [Service("npns:u")] + class INpnsUser : IpcService + { + public INpnsUser(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/IDevelopInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IDevelopInterface.cs new file mode 100644 index 00000000..c74ebd69 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ns/IDevelopInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ns +{ + [Service("ns:dev")] + class IDevelopInterface : IpcService + { + public IDevelopInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs index a8c9ff9a..71331667 100644 --- a/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs @@ -2,6 +2,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns { [Service("ns:am2")] [Service("ns:ec")] + [Service("ns:rid")] + [Service("ns:rt")] + [Service("ns:web")] class IServiceGetterInterface : IpcService { public IServiceGetterInterface(ServiceCtx context) { } diff --git a/Ryujinx.HLE/HOS/Services/Nsd/FqdnResolver.cs b/Ryujinx.HLE/HOS/Services/Nsd/FqdnResolver.cs deleted file mode 100644 index 10b6433a..00000000 --- a/Ryujinx.HLE/HOS/Services/Nsd/FqdnResolver.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Nsd -{ - class FqdnResolver - { - private const string _dummyAddress = "unknown.dummy.nintendo.net"; - - private NsdSettings _nsdSettings; - - public FqdnResolver(NsdSettings nsdSettings) - { - _nsdSettings = nsdSettings; - } - - public ResultCode GetSettingName(ServiceCtx context, out string settingName) - { - if (_nsdSettings.TestMode) - { - settingName = ""; - - return ResultCode.NotImplemented; - } - else - { - settingName = ""; - - if (true) // TODO: Determine field (struct + 0x2C) - { - settingName = _nsdSettings.Environment; - - return ResultCode.Success; - } - - return ResultCode.NullOutputObject; - } - } - - public ResultCode GetEnvironmentIdentifier(ServiceCtx context, out string identifier) - { - if (_nsdSettings.TestMode) - { - identifier = "rre"; - - return ResultCode.NotImplemented; - } - else - { - identifier = _nsdSettings.Environment; - } - - return ResultCode.Success; - } - - public ResultCode Resolve(ServiceCtx context, string address, out string resolvedAddress) - { - if (address != "api.sect.srv.nintendo.net" || address != "conntest.nintendowifi.net") - { - // TODO: Load Environment from the savedata. - address = address.Replace("%", _nsdSettings.Environment); - - resolvedAddress = ""; - - if (_nsdSettings == null) - { - return ResultCode.SettingsNotInitialized; - } - - if (!_nsdSettings.Initialized) - { - return ResultCode.SettingsNotLoaded; - } - - switch (address) - { - case "e97b8a9d672e4ce4845ec6947cd66ef6-sb-api.accounts.nintendo.com": // dp1 environment - resolvedAddress = "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com"; - break; - case "api.accounts.nintendo.com": // dp1 environment - resolvedAddress = "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com"; - break; - case "e97b8a9d672e4ce4845ec6947cd66ef6-sb.accounts.nintendo.com": // lp1 environment - resolvedAddress = "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com"; - break; - case "accounts.nintendo.com": // lp1 environment - resolvedAddress = "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com"; - break; - /* - // TODO: Determine fields of the struct. - case "": // + 0xEB8 || + 0x2BE8 - resolvedAddress = ""; // + 0xEB8 + 0x300 || + 0x2BE8 + 0x300 - break; - */ - default: - resolvedAddress = address; - break; - } - } - else - { - resolvedAddress = address; - } - - return ResultCode.Success; - } - - public ResultCode ResolveEx(ServiceCtx context, out ResultCode resultCode, out string resolvedAddress) - { - (long inputPosition, long inputSize) = context.Request.GetBufferType0x21(); - - byte[] addressBuffer = context.Memory.ReadBytes(inputPosition, inputSize); - string address = Encoding.UTF8.GetString(addressBuffer); - - resultCode = Resolve(context, address, out resolvedAddress); - - if (resultCode != ResultCode.Success) - { - resolvedAddress = _dummyAddress; - } - - if (_nsdSettings.TestMode) - { - return ResultCode.Success; - } - else - { - return resultCode; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nsd/IManager.cs b/Ryujinx.HLE/HOS/Services/Nsd/IManager.cs deleted file mode 100644 index 5dac7cf4..00000000 --- a/Ryujinx.HLE/HOS/Services/Nsd/IManager.cs +++ /dev/null @@ -1,267 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.Exceptions; -using Ryujinx.HLE.HOS.Services.Set; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Nsd -{ - [Service("nsd:a")] // Max sessions: 5 - [Service("nsd:u")] // Max sessions: 20 - class IManager : IpcService - { - private NsdSettings _nsdSettings; - private FqdnResolver _fqdnResolver; - - private bool _isInitialized = false; - - public IManager(ServiceCtx context) - { - // TODO: Load nsd settings through the savedata 0x80000000000000B0 (nsdsave:/). - - NxSettings.Settings.TryGetValue("nsd!test_mode", out object testMode); - - _nsdSettings = new NsdSettings - { - Initialized = true, - TestMode = (bool)testMode - }; - - _fqdnResolver = new FqdnResolver(_nsdSettings); - - _isInitialized = true; - } - - [Command(10)] - // GetSettingName() -> buffer, 0x16> - public ResultCode GetSettingName(ServiceCtx context) - { - (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); - - ResultCode result = _fqdnResolver.GetSettingName(context, out string settingName); - - if (result == ResultCode.Success) - { - byte[] settingNameBuffer = Encoding.UTF8.GetBytes(settingName + '\0'); - - context.Memory.WriteBytes(outputPosition, settingNameBuffer); - } - - return result; - } - - [Command(11)] - // GetEnvironmentIdentifier() -> buffer, 0x16> - public ResultCode GetEnvironmentIdentifier(ServiceCtx context) - { - (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); - - ResultCode result = _fqdnResolver.GetEnvironmentIdentifier(context, out string identifier); - - if (result == ResultCode.Success) - { - byte[] identifierBuffer = Encoding.UTF8.GetBytes(identifier + '\0'); - - context.Memory.WriteBytes(outputPosition, identifierBuffer); - } - - return result; - } - - [Command(12)] - // GetDeviceId() -> bytes<0x10, 1> - public ResultCode GetDeviceId(ServiceCtx context) - { - // NOTE: Stubbed in system module. - - return ResultCode.Success; - } - - [Command(13)] - // DeleteSettings(u32) - public ResultCode DeleteSettings(ServiceCtx context) - { - uint unknown = context.RequestData.ReadUInt32(); - - if (!_isInitialized) - { - return ResultCode.ServiceNotInitialized; - } - - if (unknown > 1) - { - return ResultCode.InvalidArgument; - } - - if (unknown == 1) - { - NxSettings.Settings.TryGetValue("nsd!environment_identifier", out object environmentIdentifier); - - if ((string)environmentIdentifier == _nsdSettings.Environment) - { - // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode. - } - else - { - // TODO: Mount the savedata file and return ResultCode. - } - } - else - { - // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode. - } - - return ResultCode.Success; - } - - [Command(14)] - // ImportSettings(u32, buffer) -> buffer - public ResultCode ImportSettings(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(15)] - // Unknown(bytes<1>) - public ResultCode Unknown(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(20)] - // Resolve(buffer, 0x15>) -> buffer, 0x16> - public ResultCode Resolve(ServiceCtx context) - { - (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); - - ResultCode result = _fqdnResolver.ResolveEx(context, out ResultCode errorCode, out string resolvedAddress); - - byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress + '\0'); - - context.Memory.WriteBytes(outputPosition, resolvedAddressBuffer); - - return result; - } - - [Command(21)] - // ResolveEx(buffer, 0x15>) -> (u32, buffer, 0x16>) - public ResultCode ResolveEx(ServiceCtx context) - { - (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); - - ResultCode result = _fqdnResolver.ResolveEx(context, out ResultCode errorCode, out string resolvedAddress); - - byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress + '\0'); - - context.Memory.WriteBytes(outputPosition, resolvedAddressBuffer); - - context.ResponseData.Write((int)errorCode); - - return result; - } - - [Command(30)] - // GetNasServiceSetting(buffer, 0x15>) -> buffer, 0x16> - public ResultCode GetNasServiceSetting(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(31)] - // GetNasServiceSettingEx(buffer, 0x15>) -> (u32, buffer, 0x16>) - public ResultCode GetNasServiceSettingEx(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(40)] - // GetNasRequestFqdn() -> buffer, 0x16> - public ResultCode GetNasRequestFqdn(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(41)] - // GetNasRequestFqdnEx() -> (u32, buffer, 0x16>) - public ResultCode GetNasRequestFqdnEx(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(42)] - // GetNasApiFqdn() -> buffer, 0x16> - public ResultCode GetNasApiFqdn(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(43)] - // GetNasApiFqdnEx() -> (u32, buffer, 0x16>) - public ResultCode GetNasApiFqdnEx(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(50)] - // GetCurrentSetting() -> buffer, 0x16> - public ResultCode GetCurrentSetting(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - - [Command(60)] - // ReadSaveDataFromFsForTest() -> buffer, 0x16> - public ResultCode ReadSaveDataFromFsForTest(ServiceCtx context) - { - if (!_isInitialized) - { - return ResultCode.ServiceNotInitialized; - } - - // TODO: Call nn::nsd::detail::fs::ReadSaveDataWithOffset() at offset 0 to write the - // whole savedata inside the buffer. - - Logger.PrintStub(LogClass.ServiceNsd); - - return ResultCode.Success; - } - - [Command(61)] - // WriteSaveDataToFsForTest(buffer, 0x15>) - public ResultCode WriteSaveDataToFsForTest(ServiceCtx context) - { - // NOTE: Stubbed in system module. - - if (_isInitialized) - { - return ResultCode.NotImplemented; - } - else - { - return ResultCode.ServiceNotInitialized; - } - } - - [Command(62)] - // DeleteSaveDataOfFsForTest() - public ResultCode DeleteSaveDataOfFsForTest(ServiceCtx context) - { - // NOTE: Stubbed in system module. - - if (_isInitialized) - { - return ResultCode.NotImplemented; - } - else - { - return ResultCode.ServiceNotInitialized; - } - } - - [Command(63)] - // IsChangeEnvironmentIdentifierDisabled() -> bytes<1> - public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context) - { - throw new ServiceNotImplementedException(context); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nsd/NsdSettings.cs b/Ryujinx.HLE/HOS/Services/Nsd/NsdSettings.cs deleted file mode 100644 index 42739df0..00000000 --- a/Ryujinx.HLE/HOS/Services/Nsd/NsdSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nsd -{ - class NsdSettings - { - public bool Initialized; - public bool TestMode; - public string Environment = "lp1"; // or "dd1" if devkit. - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nsd/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Nsd/ResultCode.cs deleted file mode 100644 index 27584eb1..00000000 --- a/Ryujinx.HLE/HOS/Services/Nsd/ResultCode.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nsd -{ - enum ResultCode - { - ModuleId = 141, - ErrorCodeShift = 9, - - Success = 0, - - NotImplemented = ( 1 << ErrorCodeShift) | ModuleId, - InvalidObject1 = ( 3 << ErrorCodeShift) | ModuleId, - InvalidObject2 = ( 4 << ErrorCodeShift) | ModuleId, - NullOutputObject = ( 5 << ErrorCodeShift) | ModuleId, - SettingsNotLoaded = ( 6 << ErrorCodeShift) | ModuleId, - InvalidArgument = ( 8 << ErrorCodeShift) | ModuleId, - SettingsNotInitialized = ( 10 << ErrorCodeShift) | ModuleId, - ServiceNotInitialized = (400 << ErrorCodeShift) | ModuleId, - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvDebugFSServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvDebugFSServices.cs new file mode 100644 index 00000000..dffe8783 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvDebugFSServices.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + [Service("nvdrvdbg")] + class INvDrvDebugFSServices : IpcService + { + public INvDrvDebugFSServices(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 261c1c5a..da34421b 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -4,11 +4,11 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; -using Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu; -using Ryujinx.HLE.HOS.Services.Nv.NvHostChannel; -using Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl; -using Ryujinx.HLE.HOS.Services.Nv.NvMap; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using System; using System.Collections.Generic; diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvGemControl.cs b/Ryujinx.HLE/HOS/Services/Nv/INvGemControl.cs new file mode 100644 index 00000000..7bf99ed1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/INvGemControl.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + [Service("nvgem:c")] + class INvGemControl : IpcService + { + public INvGemControl(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvGemCoreDump.cs b/Ryujinx.HLE/HOS/Services/Nv/INvGemCoreDump.cs new file mode 100644 index 00000000..ff3774da --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/INvGemCoreDump.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + [Service("nvgem:cd")] + class INvGemCoreDump : IpcService + { + public INvGemCoreDump(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs new file mode 100644 index 00000000..5c8d1fe0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs @@ -0,0 +1,330 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + class NvGpuASIoctl + { + private const int FlagFixedOffset = 1; + + private const int FlagRemapSubRange = 0x100; + + private static ConcurrentDictionary _asCtxs; + + static NvGpuASIoctl() + { + _asCtxs = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx context, int cmd) + { + switch (cmd & 0xffff) + { + case 0x4101: return BindChannel (context); + case 0x4102: return AllocSpace (context); + case 0x4103: return FreeSpace (context); + case 0x4105: return UnmapBuffer (context); + case 0x4106: return MapBufferEx (context); + case 0x4108: return GetVaRegions(context); + case 0x4109: return InitializeEx(context); + case 0x4114: return Remap (context, cmd); + } + + throw new NotImplementedException(cmd.ToString("x8")); + } + + private static int BindChannel(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int AllocSpace(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuASCtx asCtx = GetASCtx(context); + + ulong size = (ulong)args.Pages * + (ulong)args.PageSize; + + int result = NvResult.Success; + + lock (asCtx) + { + // Note: When the fixed offset flag is not set, + // the Offset field holds the alignment size instead. + if ((args.Flags & FlagFixedOffset) != 0) + { + args.Offset = asCtx.Vmm.ReserveFixed(args.Offset, (long)size); + } + else + { + args.Offset = asCtx.Vmm.Reserve((long)size, args.Offset); + } + + if (args.Offset < 0) + { + args.Offset = 0; + + Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); + + result = NvResult.OutOfMemory; + } + else + { + asCtx.AddReservation(args.Offset, (long)size); + } + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return result; + } + + private static int FreeSpace(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuASCtx asCtx = GetASCtx(context); + + int result = NvResult.Success; + + lock (asCtx) + { + ulong size = (ulong)args.Pages * + (ulong)args.PageSize; + + if (asCtx.RemoveReservation(args.Offset)) + { + asCtx.Vmm.Free(args.Offset, (long)size); + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, + $"Failed to free offset 0x{args.Offset:x16} size 0x{size:x16}!"); + + result = NvResult.InvalidInput; + } + } + + return result; + } + + private static int UnmapBuffer(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuASUnmapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuASCtx asCtx = GetASCtx(context); + + lock (asCtx) + { + if (asCtx.RemoveMap(args.Offset, out long size)) + { + if (size != 0) + { + asCtx.Vmm.Free(args.Offset, size); + } + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {args.Offset:x16}!"); + } + } + + return NvResult.Success; + } + + private static int MapBufferEx(ServiceCtx context) + { + const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; + + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuASMapBufferEx args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuASCtx asCtx = GetASCtx(context); + + NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + + long pa; + + if ((args.Flags & FlagRemapSubRange) != 0) + { + lock (asCtx) + { + if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa)) + { + long va = args.Offset + args.BufferOffset; + + pa += args.BufferOffset; + + if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0) + { + string msg = string.Format(mapErrorMsg, va, args.MappingSize); + + Logger.PrintWarning(LogClass.ServiceNv, msg); + + return NvResult.InvalidInput; + } + + return NvResult.Success; + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!"); + + return NvResult.InvalidInput; + } + } + } + + pa = map.Address + args.BufferOffset; + + long size = args.MappingSize; + + if (size == 0) + { + size = (uint)map.Size; + } + + int result = NvResult.Success; + + lock (asCtx) + { + // Note: When the fixed offset flag is not set, + // the Offset field holds the alignment size instead. + bool vaAllocated = (args.Flags & FlagFixedOffset) == 0; + + if (!vaAllocated) + { + if (asCtx.ValidateFixedBuffer(args.Offset, size)) + { + args.Offset = asCtx.Vmm.Map(pa, args.Offset, size); + } + else + { + string msg = string.Format(mapErrorMsg, args.Offset, size); + + Logger.PrintWarning(LogClass.ServiceNv, msg); + + result = NvResult.InvalidInput; + } + } + else + { + args.Offset = asCtx.Vmm.Map(pa, size); + } + + if (args.Offset < 0) + { + args.Offset = 0; + + Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); + + result = NvResult.InvalidInput; + } + else + { + asCtx.AddMap(args.Offset, size, pa, vaAllocated); + } + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return result; + } + + private static int GetVaRegions(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int InitializeEx(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int Remap(ServiceCtx context, int cmd) + { + int count = ((cmd >> 16) & 0xff) / 0x14; + + long inputPosition = context.Request.GetBufferType0x21().Position; + + for (int index = 0; index < count; index++, inputPosition += 0x14) + { + NvGpuASRemap args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = GetASCtx(context).Vmm; + + NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + + long result = vmm.Map(map.Address, (long)(uint)args.Offset << 16, + (long)(uint)args.Pages << 16); + + if (result < 0) + { + Logger.PrintWarning(LogClass.ServiceNv, + $"Page 0x{args.Offset:x16} size 0x{args.Pages:x16} not allocated!"); + + return NvResult.InvalidInput; + } + } + + return NvResult.Success; + } + + public static NvGpuASCtx GetASCtx(ServiceCtx context) + { + return _asCtxs.GetOrAdd(context.Process, (key) => new NvGpuASCtx(context)); + } + + public static void UnloadProcess(KProcess process) + { + _asCtxs.TryRemove(process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs new file mode 100644 index 00000000..f0a0db35 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + struct NvGpuASAllocSpace + { + public int Pages; + public int PageSize; + public int Flags; + public int Padding; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs new file mode 100644 index 00000000..315fe353 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs @@ -0,0 +1,200 @@ +using Ryujinx.Graphics.Memory; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + class NvGpuASCtx + { + public NvGpuVmm Vmm { get; private set; } + + private class Range + { + public ulong Start { get; private set; } + public ulong End { get; private set; } + + public Range(long position, long size) + { + Start = (ulong)position; + End = (ulong)size + Start; + } + } + + private class MappedMemory : Range + { + public long PhysicalAddress { get; private set; } + public bool VaAllocated { get; private set; } + + public MappedMemory( + long position, + long size, + long physicalAddress, + bool vaAllocated) : base(position, size) + { + PhysicalAddress = physicalAddress; + VaAllocated = vaAllocated; + } + } + + private SortedList _maps; + private SortedList _reservations; + + public NvGpuASCtx(ServiceCtx context) + { + Vmm = new NvGpuVmm(context.Memory); + + _maps = new SortedList(); + _reservations = new SortedList(); + } + + public bool ValidateFixedBuffer(long position, long size) + { + long mapEnd = position + size; + + // Check if size is valid (0 is also not allowed). + if ((ulong)mapEnd <= (ulong)position) + { + return false; + } + + // Check if address is page aligned. + if ((position & NvGpuVmm.PageMask) != 0) + { + return false; + } + + // Check if region is reserved. + if (BinarySearch(_reservations, position) == null) + { + return false; + } + + // Check for overlap with already mapped buffers. + Range map = BinarySearchLt(_maps, mapEnd); + + if (map != null && map.End > (ulong)position) + { + return false; + } + + return true; + } + + public void AddMap( + long position, + long size, + long physicalAddress, + bool vaAllocated) + { + _maps.Add(position, new MappedMemory(position, size, physicalAddress, vaAllocated)); + } + + public bool RemoveMap(long position, out long size) + { + size = 0; + + if (_maps.Remove(position, out Range value)) + { + MappedMemory map = (MappedMemory)value; + + if (map.VaAllocated) + { + size = (long)(map.End - map.Start); + } + + return true; + } + + return false; + } + + public bool TryGetMapPhysicalAddress(long position, out long physicalAddress) + { + Range map = BinarySearch(_maps, position); + + if (map != null) + { + physicalAddress = ((MappedMemory)map).PhysicalAddress; + + return true; + } + + physicalAddress = 0; + + return false; + } + + public void AddReservation(long position, long size) + { + _reservations.Add(position, new Range(position, size)); + } + + public bool RemoveReservation(long position) + { + return _reservations.Remove(position); + } + + private Range BinarySearch(SortedList lst, long position) + { + int left = 0; + int right = lst.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + Range rg = lst.Values[middle]; + + if ((ulong)position >= rg.Start && (ulong)position < rg.End) + { + return rg; + } + + if ((ulong)position < rg.Start) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return null; + } + + private Range BinarySearchLt(SortedList lst, long position) + { + Range ltRg = null; + + int left = 0; + int right = lst.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + Range rg = lst.Values[middle]; + + if ((ulong)position < rg.Start) + { + right = middle - 1; + } + else + { + left = middle + 1; + + if ((ulong)position > rg.Start) + { + ltRg = rg; + } + } + } + + return ltRg; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs new file mode 100644 index 00000000..6ef80377 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + struct NvGpuASMapBufferEx + { + public int Flags; + public int Kind; + public int NvMapHandle; + public int PageSize; + public long BufferOffset; + public long MappingSize; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs new file mode 100644 index 00000000..0a6f8003 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + struct NvGpuASRemap + { + public short Flags; + public short Kind; + public int NvMapHandle; + public int Padding; + public int Offset; + public int Pages; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs new file mode 100644 index 00000000..63476b2f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +{ + struct NvGpuASUnmapBuffer + { + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs new file mode 100644 index 00000000..12f13153 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs @@ -0,0 +1,190 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using System; +using System.Diagnostics; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + class NvGpuGpuIoctl + { + private static Stopwatch _pTimer; + + private static double _ticksToNs; + + static NvGpuGpuIoctl() + { + _pTimer = new Stopwatch(); + + _pTimer.Start(); + + _ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; + } + + public static int ProcessIoctl(ServiceCtx context, int cmd) + { + switch (cmd & 0xffff) + { + case 0x4701: return ZcullGetCtxSize (context); + case 0x4702: return ZcullGetInfo (context); + case 0x4703: return ZbcSetTable (context); + case 0x4705: return GetCharacteristics(context); + case 0x4706: return GetTpcMasks (context); + case 0x4714: return GetActiveSlotMask (context); + case 0x471c: return GetGpuTime (context); + } + + throw new NotImplementedException(cmd.ToString("x8")); + } + + private static int ZcullGetCtxSize(ServiceCtx context) + { + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuGpuZcullGetCtxSize args = new NvGpuGpuZcullGetCtxSize + { + Size = 1 + }; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int ZcullGetInfo(ServiceCtx context) + { + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuGpuZcullGetInfo args = new NvGpuGpuZcullGetInfo + { + WidthAlignPixels = 0x20, + HeightAlignPixels = 0x20, + PixelSquaresByAliquots = 0x400, + AliquotTotal = 0x800, + RegionByteMultiplier = 0x20, + RegionHeaderSize = 0x20, + SubregionHeaderSize = 0xc0, + SubregionWidthAlignPixels = 0x20, + SubregionHeightAlignPixels = 0x40, + SubregionCount = 0x10 + }; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int ZbcSetTable(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int GetCharacteristics(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetCharacteristics args = MemoryHelper.Read(context.Memory, inputPosition); + + args.BufferSize = 0xa0; + + args.Arch = 0x120; + args.Impl = 0xb; + args.Rev = 0xa1; + args.NumGpc = 0x1; + args.L2CacheSize = 0x40000; + args.OnBoardVideoMemorySize = 0x0; + args.NumTpcPerGpc = 0x2; + args.BusType = 0x20; + args.BigPageSize = 0x20000; + args.CompressionPageSize = 0x20000; + args.PdeCoverageBitCount = 0x1b; + args.AvailableBigPageSizes = 0x30000; + args.GpcMask = 0x1; + args.SmArchSmVersion = 0x503; + args.SmArchSpaVersion = 0x503; + args.SmArchWarpCount = 0x80; + args.GpuVaBitCount = 0x28; + args.Reserved = 0x0; + args.Flags = 0x55; + args.TwodClass = 0x902d; + args.ThreedClass = 0xb197; + args.ComputeClass = 0xb1c0; + args.GpfifoClass = 0xb06f; + args.InlineToMemoryClass = 0xa140; + args.DmaCopyClass = 0xb0b5; + args.MaxFbpsCount = 0x1; + args.FbpEnMask = 0x0; + args.MaxLtcPerFbp = 0x2; + args.MaxLtsPerLtc = 0x1; + args.MaxTexPerTpc = 0x0; + args.MaxGpcCount = 0x1; + args.RopL2EnMask0 = 0x21d70; + args.RopL2EnMask1 = 0x0; + args.ChipName = 0x6230326d67; + args.GrCompbitStoreBaseHw = 0x0; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int GetTpcMasks(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetTpcMasks args = MemoryHelper.Read(context.Memory, inputPosition); + + if (args.MaskBufferSize != 0) + { + args.TpcMask = 3; + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int GetActiveSlotMask(ServiceCtx context) + { + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetActiveSlotMask args = new NvGpuGpuGetActiveSlotMask + { + Slot = 0x07, + Mask = 0x01 + }; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int GetGpuTime(ServiceCtx context) + { + long outputPosition = context.Request.GetBufferType0x22().Position; + + context.Memory.WriteInt64(outputPosition, GetPTimerNanoSeconds()); + + return NvResult.Success; + } + + private static long GetPTimerNanoSeconds() + { + double ticks = _pTimer.ElapsedTicks; + + return (long)(ticks * _ticksToNs) & 0xff_ffff_ffff_ffff; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs new file mode 100644 index 00000000..1b4c5345 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + struct NvGpuGpuGetActiveSlotMask + { + public int Slot; + public int Mask; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs new file mode 100644 index 00000000..76aef2a7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + struct NvGpuGpuGetCharacteristics + { + public long BufferSize; + public long BufferAddress; + public int Arch; + public int Impl; + public int Rev; + public int NumGpc; + public long L2CacheSize; + public long OnBoardVideoMemorySize; + public int NumTpcPerGpc; + public int BusType; + public int BigPageSize; + public int CompressionPageSize; + public int PdeCoverageBitCount; + public int AvailableBigPageSizes; + public int GpcMask; + public int SmArchSmVersion; + public int SmArchSpaVersion; + public int SmArchWarpCount; + public int GpuVaBitCount; + public int Reserved; + public long Flags; + public int TwodClass; + public int ThreedClass; + public int ComputeClass; + public int GpfifoClass; + public int InlineToMemoryClass; + public int DmaCopyClass; + public int MaxFbpsCount; + public int FbpEnMask; + public int MaxLtcPerFbp; + public int MaxLtsPerLtc; + public int MaxTexPerTpc; + public int MaxGpcCount; + public int RopL2EnMask0; + public int RopL2EnMask1; + public long ChipName; + public long GrCompbitStoreBaseHw; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs new file mode 100644 index 00000000..bc0966da --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + struct NvGpuGpuGetTpcMasks + { + public int MaskBufferSize; + public int Reserved; + public long MaskBufferAddress; + public int TpcMask; + public int Padding; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs new file mode 100644 index 00000000..8706d51d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + struct NvGpuGpuZcullGetCtxSize + { + public int Size; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs new file mode 100644 index 00000000..ab17ca8b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +{ + struct NvGpuGpuZcullGetInfo + { + public int WidthAlignPixels; + public int HeightAlignPixels; + public int PixelSquaresByAliquots; + public int AliquotTotal; + public int RegionByteMultiplier; + public int RegionHeaderSize; + public int SubregionHeaderSize; + public int SubregionWidthAlignPixels; + public int SubregionHeightAlignPixels; + public int SubregionCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs new file mode 100644 index 00000000..0d06e7e4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs @@ -0,0 +1,371 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + class NvHostChannelIoctl + { + private static ConcurrentDictionary _channels; + + static NvHostChannelIoctl() + { + _channels = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx context, int cmd) + { + switch (cmd & 0xffff) + { + case 0x0001: return Submit (context); + case 0x0002: return GetSyncpoint (context); + case 0x0003: return GetWaitBase (context); + case 0x0007: return SetSubmitTimeout (context); + case 0x0009: return MapBuffer (context); + case 0x000a: return UnmapBuffer (context); + case 0x4714: return SetUserData (context); + case 0x4801: return SetNvMap (context); + case 0x4803: return SetTimeout (context); + case 0x4808: return SubmitGpfifo (context); + case 0x4809: return AllocObjCtx (context); + case 0x480b: return ZcullBind (context); + case 0x480c: return SetErrorNotifier (context); + case 0x480d: return SetPriority (context); + case 0x481a: return AllocGpfifoEx2 (context); + case 0x481b: return KickoffPbWithAttr(context); + case 0x481d: return SetTimeslice (context); + } + + throw new NotImplementedException(cmd.ToString("x8")); + } + + private static int Submit(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmit args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + for (int index = 0; index < args.CmdBufsCount; index++) + { + long cmdBufOffset = inputPosition + 0x10 + index * 0xc; + + NvHostChannelCmdBuf cmdBuf = MemoryHelper.Read(context.Memory, cmdBufOffset); + + NvMapHandle map = NvMapIoctl.GetNvMap(context, cmdBuf.MemoryId); + + int[] cmdBufData = new int[cmdBuf.WordsCount]; + + for (int offset = 0; offset < cmdBufData.Length; offset++) + { + cmdBufData[offset] = context.Memory.ReadInt32(map.Address + cmdBuf.Offset + offset * 4); + } + + context.Device.Gpu.PushCommandBuffer(vmm, cmdBufData); + } + + // TODO: Relocation, waitchecks, etc. + + return NvResult.Success; + } + + private static int GetSyncpoint(ServiceCtx context) + { + // TODO + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelGetParamArg args = MemoryHelper.Read(context.Memory, inputPosition); + + args.Value = 0; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int GetWaitBase(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelGetParamArg args = MemoryHelper.Read(context.Memory, inputPosition); + + args.Value = 0; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int SetSubmitTimeout(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + + GetChannel(context).SubmitTimeout = context.Memory.ReadInt32(inputPosition); + + // TODO: Handle the timeout in the submit method. + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int MapBuffer(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + for (int index = 0; index < args.NumEntries; index++) + { + int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); + + NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); + + return NvResult.InvalidInput; + } + + lock (map) + { + if (map.DmaMapAddress == 0) + { + map.DmaMapAddress = vmm.MapLow(map.Address, map.Size); + } + + context.Memory.WriteInt32(outputPosition + 0xc + 4 + index * 8, (int)map.DmaMapAddress); + } + } + + return NvResult.Success; + } + + private static int UnmapBuffer(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + + NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + for (int index = 0; index < args.NumEntries; index++) + { + int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); + + NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); + + return NvResult.InvalidInput; + } + + lock (map) + { + if (map.DmaMapAddress != 0) + { + vmm.Free(map.DmaMapAddress, map.Size); + + map.DmaMapAddress = 0; + } + } + } + + return NvResult.Success; + } + + private static int SetUserData(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SetNvMap(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SetTimeout(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + + GetChannel(context).Timeout = context.Memory.ReadInt32(inputPosition); + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SubmitGpfifo(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + for (int index = 0; index < args.NumEntries; index++) + { + long gpfifo = context.Memory.ReadInt64(inputPosition + 0x18 + index * 8); + + PushGpfifo(context, vmm, gpfifo); + } + + args.SyncptId = 0; + args.SyncptValue = 0; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int AllocObjCtx(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int ZcullBind(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SetErrorNotifier(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SetPriority(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + + switch ((NvChannelPriority)context.Memory.ReadInt32(inputPosition)) + { + case NvChannelPriority.Low: + GetChannel(context).Timeslice = 1300; // Timeslice low priority in micro-seconds + break; + case NvChannelPriority.Medium: + GetChannel(context).Timeslice = 2600; // Timeslice medium priority in micro-seconds + break; + case NvChannelPriority.High: + GetChannel(context).Timeslice = 5200; // Timeslice high priority in micro-seconds + break; + default: + return NvResult.InvalidInput; + } + + Logger.PrintStub(LogClass.ServiceNv); + + // TODO: disable and preempt channel when GPU scheduler will be implemented. + + return NvResult.Success; + } + + private static int AllocGpfifoEx2(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int KickoffPbWithAttr(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); + + NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + + for (int index = 0; index < args.NumEntries; index++) + { + long gpfifo = context.Memory.ReadInt64(args.Address + index * 8); + + PushGpfifo(context, vmm, gpfifo); + } + + args.SyncptId = 0; + args.SyncptValue = 0; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int SetTimeslice(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + int timeslice = context.Memory.ReadInt32(inputPosition); + + if (timeslice < 1000 || timeslice > 50000) + { + return NvResult.InvalidInput; + } + + GetChannel(context).Timeslice = timeslice; // in micro-seconds + + Logger.PrintStub(LogClass.ServiceNv); + + // TODO: disable and preempt channel when GPU scheduler will be implemented. + + return NvResult.Success; + } + + private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo) + { + context.Device.Gpu.Pusher.Push(vmm, gpfifo); + } + + public static NvChannel GetChannel(ServiceCtx context) + { + return _channels.GetOrAdd(context.Process, (key) => new NvChannel()); + } + + public static void UnloadProcess(KProcess process) + { + _channels.TryRemove(process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannel.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannel.cs new file mode 100644 index 00000000..22cfba3d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannel.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + class NvChannel + { + public int Timeout; + public int SubmitTimeout; + public int Timeslice; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannelPriority.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannelPriority.cs new file mode 100644 index 00000000..148a640b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvChannelPriority.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + enum NvChannelPriority + { + Low = 50, + Medium = 100, + High = 150 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelCmdBuf.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelCmdBuf.cs new file mode 100644 index 00000000..0308912b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelCmdBuf.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelCmdBuf + { + public int MemoryId; + public int Offset; + public int WordsCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelGetParamArg.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelGetParamArg.cs new file mode 100644 index 00000000..72946484 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelGetParamArg.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelGetParamArg + { + public int Param; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelMapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelMapBuffer.cs new file mode 100644 index 00000000..f516588e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelMapBuffer.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 4)] + struct NvHostChannelMapBuffer + { + public int NumEntries; + public int DataAddress; // Ignored by the driver. + public bool AttachHostChDas; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmit.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmit.cs new file mode 100644 index 00000000..ef2f24e7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmit.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelSubmit + { + public int CmdBufsCount; + public int RelocsCount; + public int SyncptIncrsCount; + public int WaitchecksCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmitGpfifo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmitGpfifo.cs new file mode 100644 index 00000000..e8cb5f0f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/NvHostChannelSubmitGpfifo.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + struct NvHostChannelSubmitGpfifo + { + public long Address; + public int NumEntries; + public int Flags; + public int SyncptId; + public int SyncptValue; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs new file mode 100644 index 00000000..346e2dc7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs @@ -0,0 +1,400 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Settings; +using System; +using System.Collections.Concurrent; +using System.Text; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + class NvHostCtrlIoctl + { + private static ConcurrentDictionary _userCtxs; + + private static bool _isProductionMode = true; + + static NvHostCtrlIoctl() + { + _userCtxs = new ConcurrentDictionary(); + + if (NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting)) + { + _isProductionMode = ((string)productionModeSetting) != "0"; // Default value is "" + } + } + + public static int ProcessIoctl(ServiceCtx context, int cmd) + { + switch (cmd & 0xffff) + { + case 0x0014: return SyncptRead (context); + case 0x0015: return SyncptIncr (context); + case 0x0016: return SyncptWait (context); + case 0x0019: return SyncptWaitEx (context); + case 0x001a: return SyncptReadMax (context); + case 0x001b: return GetConfig (context); + case 0x001d: return EventWait (context); + case 0x001e: return EventWaitAsync(context); + case 0x001f: return EventRegister (context); + } + + throw new NotImplementedException(cmd.ToString("x8")); + } + + private static int SyncptRead(ServiceCtx context) + { + return SyncptReadMinOrMax(context, max: false); + } + + private static int SyncptIncr(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + + int id = context.Memory.ReadInt32(inputPosition); + + if ((uint)id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + GetUserCtx(context).Syncpt.Increment(id); + + return NvResult.Success; + } + + private static int SyncptWait(ServiceCtx context) + { + return SyncptWait(context, extended: false); + } + + private static int SyncptWaitEx(ServiceCtx context) + { + return SyncptWait(context, extended: true); + } + + private static int SyncptReadMax(ServiceCtx context) + { + return SyncptReadMinOrMax(context, max: true); + } + + private static int GetConfig(ServiceCtx context) + { + if (!_isProductionMode) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + string domain = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0, 0x41); + string name = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0x41, 0x41); + + if (NxSettings.Settings.TryGetValue($"{domain}!{name}", out object nvSetting)) + { + byte[] settingBuffer = new byte[0x101]; + + if (nvSetting is string stringValue) + { + if (stringValue.Length > 0x100) + { + Logger.PrintError(LogClass.ServiceNv, $"{domain}!{name} String value size is too big!"); + } + else + { + settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0"); + } + } + + if (nvSetting is int intValue) + { + settingBuffer = BitConverter.GetBytes(intValue); + } + else if (nvSetting is bool boolValue) + { + settingBuffer[0] = boolValue ? (byte)1 : (byte)0; + } + else + { + throw new NotImplementedException(nvSetting.GetType().Name); + } + + context.Memory.WriteBytes(outputPosition + 0x82, settingBuffer); + + Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {domain}!{name}"); + } + + return NvResult.Success; + } + + return NvResult.NotAvailableInProduction; + } + + private static int EventWait(ServiceCtx context) + { + return EventWait(context, async: false); + } + + private static int EventWaitAsync(ServiceCtx context) + { + return EventWait(context, async: true); + } + + private static int EventRegister(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + int eventId = context.Memory.ReadInt32(inputPosition); + + Logger.PrintStub(LogClass.ServiceNv); + + return NvResult.Success; + } + + private static int SyncptReadMinOrMax(ServiceCtx context, bool max) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptRead args = MemoryHelper.Read(context.Memory, inputPosition); + + if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + if (max) + { + args.Value = GetUserCtx(context).Syncpt.GetMax(args.Id); + } + else + { + args.Value = GetUserCtx(context).Syncpt.GetMin(args.Id); + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int SyncptWait(ServiceCtx context, bool extended) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptWait args = MemoryHelper.Read(context.Memory, inputPosition); + + NvHostSyncpt syncpt = GetUserCtx(context).Syncpt; + + if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + int result; + + if (syncpt.MinCompare(args.Id, args.Thresh)) + { + result = NvResult.Success; + } + else if (args.Timeout == 0) + { + result = NvResult.TryAgain; + } + else + { + Logger.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + args.Timeout + "ms..."); + + using (ManualResetEvent waitEvent = new ManualResetEvent(false)) + { + syncpt.AddWaiter(args.Thresh, waitEvent); + + // Note: Negative (> INT_MAX) timeouts aren't valid on .NET, + // in this case we just use the maximum timeout possible. + int timeout = args.Timeout; + + if (timeout < -1) + { + timeout = int.MaxValue; + } + + if (timeout == -1) + { + waitEvent.WaitOne(); + + result = NvResult.Success; + } + else if (waitEvent.WaitOne(timeout)) + { + result = NvResult.Success; + } + else + { + result = NvResult.TimedOut; + } + } + + Logger.PrintDebug(LogClass.ServiceNv, "Resuming..."); + } + + if (extended) + { + context.Memory.WriteInt32(outputPosition + 0xc, syncpt.GetMin(args.Id)); + } + + return result; + } + + private static int EventWait(ServiceCtx context, bool async) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptWaitEx args = MemoryHelper.Read(context.Memory, inputPosition); + + if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + void WriteArgs() + { + MemoryHelper.Write(context.Memory, outputPosition, args); + } + + NvHostSyncpt syncpt = GetUserCtx(context).Syncpt; + + if (syncpt.MinCompare(args.Id, args.Thresh)) + { + args.Value = syncpt.GetMin(args.Id); + + WriteArgs(); + + return NvResult.Success; + } + + if (!async) + { + args.Value = 0; + } + + if (args.Timeout == 0) + { + WriteArgs(); + + return NvResult.TryAgain; + } + + NvHostEvent Event; + + int result, eventIndex; + + if (async) + { + eventIndex = args.Value; + + if ((uint)eventIndex >= NvHostCtrlUserCtx.EventsCount) + { + return NvResult.InvalidInput; + } + + Event = GetUserCtx(context).Events[eventIndex]; + } + else + { + Event = GetFreeEvent(context, syncpt, args.Id, out eventIndex); + } + + if (Event != null && + (Event.State == NvHostEventState.Registered || + Event.State == NvHostEventState.Free)) + { + Event.Id = args.Id; + Event.Thresh = args.Thresh; + + Event.State = NvHostEventState.Waiting; + + if (!async) + { + args.Value = ((args.Id & 0xfff) << 16) | 0x10000000; + } + else + { + args.Value = args.Id << 4; + } + + args.Value |= eventIndex; + + result = NvResult.TryAgain; + } + else + { + result = NvResult.InvalidInput; + } + + WriteArgs(); + + return result; + } + + private static NvHostEvent GetFreeEvent( + ServiceCtx context, + NvHostSyncpt syncpt, + int id, + out int eventIndex) + { + NvHostEvent[] events = GetUserCtx(context).Events; + + eventIndex = NvHostCtrlUserCtx.EventsCount; + + int nullIndex = NvHostCtrlUserCtx.EventsCount; + + for (int index = 0; index < NvHostCtrlUserCtx.EventsCount; index++) + { + NvHostEvent Event = events[index]; + + if (Event != null) + { + if (Event.State == NvHostEventState.Registered || + Event.State == NvHostEventState.Free) + { + eventIndex = index; + + if (Event.Id == id) + { + return Event; + } + } + } + else if (nullIndex == NvHostCtrlUserCtx.EventsCount) + { + nullIndex = index; + } + } + + if (nullIndex < NvHostCtrlUserCtx.EventsCount) + { + eventIndex = nullIndex; + + return events[nullIndex] = new NvHostEvent(); + } + + if (eventIndex < NvHostCtrlUserCtx.EventsCount) + { + return events[eventIndex]; + } + + return null; + } + + public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx context) + { + return _userCtxs.GetOrAdd(context.Process, (key) => new NvHostCtrlUserCtx()); + } + + public static void UnloadProcess(KProcess process) + { + _userCtxs.TryRemove(process, out _); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtRead.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtRead.cs new file mode 100644 index 00000000..8cfac571 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtRead.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + struct NvHostCtrlSyncptRead + { + public int Id; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWait.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWait.cs new file mode 100644 index 00000000..401884c4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWait.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + struct NvHostCtrlSyncptWait + { + public int Id; + public int Thresh; + public int Timeout; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWaitEx.cs new file mode 100644 index 00000000..49f573e2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlSyncPtWaitEx.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + struct NvHostCtrlSyncptWaitEx + { + public int Id; + public int Thresh; + public int Timeout; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlUserCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlUserCtx.cs new file mode 100644 index 00000000..0b9d85cf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlUserCtx.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + class NvHostCtrlUserCtx + { + public const int LocksCount = 16; + public const int EventsCount = 64; + + public NvHostSyncpt Syncpt { get; private set; } + + public NvHostEvent[] Events { get; private set; } + + public NvHostCtrlUserCtx() + { + Syncpt = new NvHostSyncpt(); + + Events = new NvHostEvent[EventsCount]; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs new file mode 100644 index 00000000..c10e256e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + class NvHostEvent + { + public int Id; + public int Thresh; + + public NvHostEventState State; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEventState.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEventState.cs new file mode 100644 index 00000000..521ae9ad --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEventState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + enum NvHostEventState + { + Registered = 0, + Waiting = 1, + Busy = 2, + Free = 5 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostSyncPt.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostSyncPt.cs new file mode 100644 index 00000000..8ef45043 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostSyncPt.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + class NvHostSyncpt + { + public const int SyncptsCount = 192; + + private int[] _counterMin; + private int[] _counterMax; + + private long _eventMask; + + private ConcurrentDictionary _waiters; + + public NvHostSyncpt() + { + _counterMin = new int[SyncptsCount]; + _counterMax = new int[SyncptsCount]; + + _waiters = new ConcurrentDictionary(); + } + + public int GetMin(int id) + { + return _counterMin[id]; + } + + public int GetMax(int id) + { + return _counterMax[id]; + } + + public int Increment(int id) + { + if (((_eventMask >> id) & 1) != 0) + { + Interlocked.Increment(ref _counterMax[id]); + } + + return IncrementMin(id); + } + + public int IncrementMin(int id) + { + int value = Interlocked.Increment(ref _counterMin[id]); + + WakeUpWaiters(id, value); + + return value; + } + + public int IncrementMax(int id) + { + return Interlocked.Increment(ref _counterMax[id]); + } + + public void AddWaiter(int threshold, EventWaitHandle waitEvent) + { + if (!_waiters.TryAdd(waitEvent, threshold)) + { + throw new InvalidOperationException(); + } + } + + public bool RemoveWaiter(EventWaitHandle waitEvent) + { + return _waiters.TryRemove(waitEvent, out _); + } + + private void WakeUpWaiters(int id, int newValue) + { + foreach (KeyValuePair kv in _waiters) + { + if (MinCompare(id, newValue, _counterMax[id], kv.Value)) + { + kv.Key.Set(); + + _waiters.TryRemove(kv.Key, out _); + } + } + } + + public bool MinCompare(int id, int threshold) + { + return MinCompare(id, _counterMin[id], _counterMax[id], threshold); + } + + private bool MinCompare(int id, int min, int max, int threshold) + { + int minDiff = min - threshold; + int maxDiff = max - threshold; + + if (((_eventMask >> id) & 1) != 0) + { + return minDiff >= 0; + } + else + { + return (uint)maxDiff >= (uint)minDiff; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs new file mode 100644 index 00000000..0b5be6e8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs @@ -0,0 +1,300 @@ +using ARMeilleure.Memory; +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.Utilities; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + class NvMapIoctl + { + private const int FlagNotFreedYet = 1; + + private static ConcurrentDictionary _maps; + + static NvMapIoctl() + { + _maps = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx context, int cmd) + { + switch (cmd & 0xffff) + { + case 0x0101: return Create(context); + case 0x0103: return FromId(context); + case 0x0104: return Alloc (context); + case 0x0105: return Free (context); + case 0x0109: return Param (context); + case 0x010e: return GetId (context); + } + + Logger.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{cmd:x8}!"); + + return NvResult.NotSupported; + } + + private static int Create(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapCreate args = MemoryHelper.Read(context.Memory, inputPosition); + + if (args.Size == 0) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{args.Size:x8}!"); + + return NvResult.InvalidInput; + } + + int size = IntUtils.AlignUp(args.Size, NvGpuVmm.PageSize); + + args.Handle = AddNvMap(context, new NvMapHandle(size)); + + Logger.PrintInfo(LogClass.ServiceNv, $"Created map {args.Handle} with size 0x{size:x8}!"); + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int FromId(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapFromId args = MemoryHelper.Read(context.Memory, inputPosition); + + NvMapHandle map = GetNvMap(context, args.Id); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + map.IncrementRefCount(); + + args.Handle = args.Id; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int Alloc(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapAlloc args = MemoryHelper.Read(context.Memory, inputPosition); + + NvMapHandle map = GetNvMap(context, args.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + if ((args.Align & (args.Align - 1)) != 0) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{args.Align:x8}!"); + + return NvResult.InvalidInput; + } + + if ((uint)args.Align < NvGpuVmm.PageSize) + { + args.Align = NvGpuVmm.PageSize; + } + + int result = NvResult.Success; + + if (!map.Allocated) + { + map.Allocated = true; + + map.Align = args.Align; + map.Kind = (byte)args.Kind; + + int size = IntUtils.AlignUp(map.Size, NvGpuVmm.PageSize); + + long address = args.Address; + + if (address == 0) + { + // When the address is zero, we need to allocate + // our own backing memory for the NvMap. + // TODO: Is this allocation inside the transfer memory? + result = NvResult.OutOfMemory; + } + + if (result == NvResult.Success) + { + map.Size = size; + map.Address = address; + } + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return result; + } + + private static int Free(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapFree args = MemoryHelper.Read(context.Memory, inputPosition); + + NvMapHandle map = GetNvMap(context, args.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + if (map.DecrementRefCount() <= 0) + { + DeleteNvMap(context, args.Handle); + + Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {args.Handle}!"); + + args.Address = map.Address; + args.Flags = 0; + } + else + { + args.Address = 0; + args.Flags = FlagNotFreedYet; + } + + args.Size = map.Size; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int Param(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapParam args = MemoryHelper.Read(context.Memory, inputPosition); + + NvMapHandle map = GetNvMap(context, args.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + switch ((NvMapHandleParam)args.Param) + { + case NvMapHandleParam.Size: args.Result = map.Size; break; + case NvMapHandleParam.Align: args.Result = map.Align; break; + case NvMapHandleParam.Heap: args.Result = 0x40000000; break; + case NvMapHandleParam.Kind: args.Result = map.Kind; break; + case NvMapHandleParam.Compr: args.Result = 0; break; + + // Note: Base is not supported and returns an error. + // Any other value also returns an error. + default: return NvResult.InvalidInput; + } + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int GetId(ServiceCtx context) + { + long inputPosition = context.Request.GetBufferType0x21().Position; + long outputPosition = context.Request.GetBufferType0x22().Position; + + NvMapGetId args = MemoryHelper.Read(context.Memory, inputPosition); + + NvMapHandle map = GetNvMap(context, args.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + args.Id = args.Handle; + + MemoryHelper.Write(context.Memory, outputPosition, args); + + return NvResult.Success; + } + + private static int AddNvMap(ServiceCtx context, NvMapHandle map) + { + IdDictionary dict = _maps.GetOrAdd(context.Process, (key) => + { + IdDictionary newDict = new IdDictionary(); + + newDict.Add(0, new NvMapHandle()); + + return newDict; + }); + + return dict.Add(map); + } + + private static bool DeleteNvMap(ServiceCtx context, int handle) + { + if (_maps.TryGetValue(context.Process, out IdDictionary dict)) + { + return dict.Delete(handle) != null; + } + + return false; + } + + public static void InitializeNvMap(ServiceCtx context) + { + IdDictionary dict = _maps.GetOrAdd(context.Process, (key) =>new IdDictionary()); + + dict.Add(0, new NvMapHandle()); + } + + public static NvMapHandle GetNvMapWithFb(ServiceCtx context, int handle) + { + if (_maps.TryGetValue(context.Process, out IdDictionary dict)) + { + return dict.GetData(handle); + } + + return null; + } + + public static NvMapHandle GetNvMap(ServiceCtx context, int handle) + { + if (handle != 0 && _maps.TryGetValue(context.Process, out IdDictionary dict)) + { + return dict.GetData(handle); + } + + return null; + } + + public static void UnloadProcess(KProcess process) + { + _maps.TryRemove(process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs new file mode 100644 index 00000000..f449b606 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapAlloc + { + public int Handle; + public int HeapMask; + public int Flags; + public int Align; + public long Kind; + public long Address; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs new file mode 100644 index 00000000..b1ccf1bc --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapCreate + { + public int Size; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs new file mode 100644 index 00000000..1d17c3a7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapFree + { + public int Handle; + public int Padding; + public long Address; + public int Size; + public int Flags; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs new file mode 100644 index 00000000..7f7f83ab --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapFromId + { + public int Id; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs new file mode 100644 index 00000000..df8fff53 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapGetId + { + public int Id; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs new file mode 100644 index 00000000..3903b77c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs @@ -0,0 +1,38 @@ +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + class NvMapHandle + { + public int Handle; + public int Id; + public int Size; + public int Align; + public int Kind; + public long Address; + public bool Allocated; + public long DmaMapAddress; + + private long _dupes; + + public NvMapHandle() + { + _dupes = 1; + } + + public NvMapHandle(int size) : this() + { + Size = size; + } + + public void IncrementRefCount() + { + Interlocked.Increment(ref _dupes); + } + + public long DecrementRefCount() + { + return Interlocked.Decrement(ref _dupes); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs new file mode 100644 index 00000000..9eb7efff --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + enum NvMapHandleParam + { + Size = 1, + Align = 2, + Base = 3, + Heap = 4, + Kind = 5, + Compr = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs new file mode 100644 index 00000000..c873a0d2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + struct NvMapParam + { + public int Handle; + public int Param; + public int Result; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs b/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs deleted file mode 100644 index b6c654e4..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv -{ - class NvFd - { - public string Name { get; private set; } - - public NvFd(string name) - { - Name = name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs deleted file mode 100644 index bca2f9f4..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - struct NvGpuASAllocSpace - { - public int Pages; - public int PageSize; - public int Flags; - public int Padding; - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs deleted file mode 100644 index e3cdf2f8..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs +++ /dev/null @@ -1,200 +0,0 @@ -using Ryujinx.Graphics.Memory; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - class NvGpuASCtx - { - public NvGpuVmm Vmm { get; private set; } - - private class Range - { - public ulong Start { get; private set; } - public ulong End { get; private set; } - - public Range(long position, long size) - { - Start = (ulong)position; - End = (ulong)size + Start; - } - } - - private class MappedMemory : Range - { - public long PhysicalAddress { get; private set; } - public bool VaAllocated { get; private set; } - - public MappedMemory( - long position, - long size, - long physicalAddress, - bool vaAllocated) : base(position, size) - { - PhysicalAddress = physicalAddress; - VaAllocated = vaAllocated; - } - } - - private SortedList _maps; - private SortedList _reservations; - - public NvGpuASCtx(ServiceCtx context) - { - Vmm = new NvGpuVmm(context.Memory); - - _maps = new SortedList(); - _reservations = new SortedList(); - } - - public bool ValidateFixedBuffer(long position, long size) - { - long mapEnd = position + size; - - // Check if size is valid (0 is also not allowed). - if ((ulong)mapEnd <= (ulong)position) - { - return false; - } - - // Check if address is page aligned. - if ((position & NvGpuVmm.PageMask) != 0) - { - return false; - } - - // Check if region is reserved. - if (BinarySearch(_reservations, position) == null) - { - return false; - } - - // Check for overlap with already mapped buffers. - Range map = BinarySearchLt(_maps, mapEnd); - - if (map != null && map.End > (ulong)position) - { - return false; - } - - return true; - } - - public void AddMap( - long position, - long size, - long physicalAddress, - bool vaAllocated) - { - _maps.Add(position, new MappedMemory(position, size, physicalAddress, vaAllocated)); - } - - public bool RemoveMap(long position, out long size) - { - size = 0; - - if (_maps.Remove(position, out Range value)) - { - MappedMemory map = (MappedMemory)value; - - if (map.VaAllocated) - { - size = (long)(map.End - map.Start); - } - - return true; - } - - return false; - } - - public bool TryGetMapPhysicalAddress(long position, out long physicalAddress) - { - Range map = BinarySearch(_maps, position); - - if (map != null) - { - physicalAddress = ((MappedMemory)map).PhysicalAddress; - - return true; - } - - physicalAddress = 0; - - return false; - } - - public void AddReservation(long position, long size) - { - _reservations.Add(position, new Range(position, size)); - } - - public bool RemoveReservation(long position) - { - return _reservations.Remove(position); - } - - private Range BinarySearch(SortedList lst, long position) - { - int left = 0; - int right = lst.Count - 1; - - while (left <= right) - { - int size = right - left; - - int middle = left + (size >> 1); - - Range rg = lst.Values[middle]; - - if ((ulong)position >= rg.Start && (ulong)position < rg.End) - { - return rg; - } - - if ((ulong)position < rg.Start) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return null; - } - - private Range BinarySearchLt(SortedList lst, long position) - { - Range ltRg = null; - - int left = 0; - int right = lst.Count - 1; - - while (left <= right) - { - int size = right - left; - - int middle = left + (size >> 1); - - Range rg = lst.Values[middle]; - - if ((ulong)position < rg.Start) - { - right = middle - 1; - } - else - { - left = middle + 1; - - if ((ulong)position > rg.Start) - { - ltRg = rg; - } - } - } - - return ltRg; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs deleted file mode 100644 index 47d15a7e..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs +++ /dev/null @@ -1,330 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Memory; -using Ryujinx.HLE.HOS.Kernel.Process; -using Ryujinx.HLE.HOS.Services.Nv.NvMap; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - class NvGpuASIoctl - { - private const int FlagFixedOffset = 1; - - private const int FlagRemapSubRange = 0x100; - - private static ConcurrentDictionary _asCtxs; - - static NvGpuASIoctl() - { - _asCtxs = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x4101: return BindChannel (context); - case 0x4102: return AllocSpace (context); - case 0x4103: return FreeSpace (context); - case 0x4105: return UnmapBuffer (context); - case 0x4106: return MapBufferEx (context); - case 0x4108: return GetVaRegions(context); - case 0x4109: return InitializeEx(context); - case 0x4114: return Remap (context, cmd); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int BindChannel(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int AllocSpace(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - ulong size = (ulong)args.Pages * - (ulong)args.PageSize; - - int result = NvResult.Success; - - lock (asCtx) - { - // Note: When the fixed offset flag is not set, - // the Offset field holds the alignment size instead. - if ((args.Flags & FlagFixedOffset) != 0) - { - args.Offset = asCtx.Vmm.ReserveFixed(args.Offset, (long)size); - } - else - { - args.Offset = asCtx.Vmm.Reserve((long)size, args.Offset); - } - - if (args.Offset < 0) - { - args.Offset = 0; - - Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); - - result = NvResult.OutOfMemory; - } - else - { - asCtx.AddReservation(args.Offset, (long)size); - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int FreeSpace(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - int result = NvResult.Success; - - lock (asCtx) - { - ulong size = (ulong)args.Pages * - (ulong)args.PageSize; - - if (asCtx.RemoveReservation(args.Offset)) - { - asCtx.Vmm.Free(args.Offset, (long)size); - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, - $"Failed to free offset 0x{args.Offset:x16} size 0x{size:x16}!"); - - result = NvResult.InvalidInput; - } - } - - return result; - } - - private static int UnmapBuffer(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASUnmapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - lock (asCtx) - { - if (asCtx.RemoveMap(args.Offset, out long size)) - { - if (size != 0) - { - asCtx.Vmm.Free(args.Offset, size); - } - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {args.Offset:x16}!"); - } - } - - return NvResult.Success; - } - - private static int MapBufferEx(ServiceCtx context) - { - const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; - - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASMapBufferEx args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long pa; - - if ((args.Flags & FlagRemapSubRange) != 0) - { - lock (asCtx) - { - if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa)) - { - long va = args.Offset + args.BufferOffset; - - pa += args.BufferOffset; - - if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0) - { - string msg = string.Format(mapErrorMsg, va, args.MappingSize); - - Logger.PrintWarning(LogClass.ServiceNv, msg); - - return NvResult.InvalidInput; - } - - return NvResult.Success; - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!"); - - return NvResult.InvalidInput; - } - } - } - - pa = map.Address + args.BufferOffset; - - long size = args.MappingSize; - - if (size == 0) - { - size = (uint)map.Size; - } - - int result = NvResult.Success; - - lock (asCtx) - { - // Note: When the fixed offset flag is not set, - // the Offset field holds the alignment size instead. - bool vaAllocated = (args.Flags & FlagFixedOffset) == 0; - - if (!vaAllocated) - { - if (asCtx.ValidateFixedBuffer(args.Offset, size)) - { - args.Offset = asCtx.Vmm.Map(pa, args.Offset, size); - } - else - { - string msg = string.Format(mapErrorMsg, args.Offset, size); - - Logger.PrintWarning(LogClass.ServiceNv, msg); - - result = NvResult.InvalidInput; - } - } - else - { - args.Offset = asCtx.Vmm.Map(pa, size); - } - - if (args.Offset < 0) - { - args.Offset = 0; - - Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); - - result = NvResult.InvalidInput; - } - else - { - asCtx.AddMap(args.Offset, size, pa, vaAllocated); - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int GetVaRegions(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int InitializeEx(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int Remap(ServiceCtx context, int cmd) - { - int count = ((cmd >> 16) & 0xff) / 0x14; - - long inputPosition = context.Request.GetBufferType0x21().Position; - - for (int index = 0; index < count; index++, inputPosition += 0x14) - { - NvGpuASRemap args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = GetASCtx(context).Vmm; - - NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long result = vmm.Map(map.Address, (long)(uint)args.Offset << 16, - (long)(uint)args.Pages << 16); - - if (result < 0) - { - Logger.PrintWarning(LogClass.ServiceNv, - $"Page 0x{args.Offset:x16} size 0x{args.Pages:x16} not allocated!"); - - return NvResult.InvalidInput; - } - } - - return NvResult.Success; - } - - public static NvGpuASCtx GetASCtx(ServiceCtx context) - { - return _asCtxs.GetOrAdd(context.Process, (key) => new NvGpuASCtx(context)); - } - - public static void UnloadProcess(KProcess process) - { - _asCtxs.TryRemove(process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs deleted file mode 100644 index 4bdb4bf7..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - struct NvGpuASMapBufferEx - { - public int Flags; - public int Kind; - public int NvMapHandle; - public int PageSize; - public long BufferOffset; - public long MappingSize; - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs deleted file mode 100644 index a24221ba..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - struct NvGpuASRemap - { - public short Flags; - public short Kind; - public int NvMapHandle; - public int Padding; - public int Offset; - public int Pages; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs deleted file mode 100644 index beb07fe2..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS -{ - struct NvGpuASUnmapBuffer - { - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs deleted file mode 100644 index e20d21f9..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetActiveSlotMask - { - public int Slot; - public int Mask; - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs deleted file mode 100644 index 9a925138..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetCharacteristics - { - public long BufferSize; - public long BufferAddress; - public int Arch; - public int Impl; - public int Rev; - public int NumGpc; - public long L2CacheSize; - public long OnBoardVideoMemorySize; - public int NumTpcPerGpc; - public int BusType; - public int BigPageSize; - public int CompressionPageSize; - public int PdeCoverageBitCount; - public int AvailableBigPageSizes; - public int GpcMask; - public int SmArchSmVersion; - public int SmArchSpaVersion; - public int SmArchWarpCount; - public int GpuVaBitCount; - public int Reserved; - public long Flags; - public int TwodClass; - public int ThreedClass; - public int ComputeClass; - public int GpfifoClass; - public int InlineToMemoryClass; - public int DmaCopyClass; - public int MaxFbpsCount; - public int FbpEnMask; - public int MaxLtcPerFbp; - public int MaxLtsPerLtc; - public int MaxTexPerTpc; - public int MaxGpcCount; - public int RopL2EnMask0; - public int RopL2EnMask1; - public long ChipName; - public long GrCompbitStoreBaseHw; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs deleted file mode 100644 index 751363c6..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetTpcMasks - { - public int MaskBufferSize; - public int Reserved; - public long MaskBufferAddress; - public int TpcMask; - public int Padding; - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs deleted file mode 100644 index 04b0c63c..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs +++ /dev/null @@ -1,187 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using System; -using System.Diagnostics; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - class NvGpuGpuIoctl - { - private static Stopwatch _pTimer; - - private static double _ticksToNs; - - static NvGpuGpuIoctl() - { - _pTimer = new Stopwatch(); - - _pTimer.Start(); - - _ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x4701: return ZcullGetCtxSize (context); - case 0x4702: return ZcullGetInfo (context); - case 0x4703: return ZbcSetTable (context); - case 0x4705: return GetCharacteristics(context); - case 0x4706: return GetTpcMasks (context); - case 0x4714: return GetActiveSlotMask (context); - case 0x471c: return GetGpuTime (context); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int ZcullGetCtxSize(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetCtxSize args = new NvGpuGpuZcullGetCtxSize(); - - args.Size = 1; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int ZcullGetInfo(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetInfo args = new NvGpuGpuZcullGetInfo(); - - args.WidthAlignPixels = 0x20; - args.HeightAlignPixels = 0x20; - args.PixelSquaresByAliquots = 0x400; - args.AliquotTotal = 0x800; - args.RegionByteMultiplier = 0x20; - args.RegionHeaderSize = 0x20; - args.SubregionHeaderSize = 0xc0; - args.SubregionWidthAlignPixels = 0x20; - args.SubregionHeightAlignPixels = 0x40; - args.SubregionCount = 0x10; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int ZbcSetTable(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int GetCharacteristics(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetCharacteristics args = MemoryHelper.Read(context.Memory, inputPosition); - - args.BufferSize = 0xa0; - - args.Arch = 0x120; - args.Impl = 0xb; - args.Rev = 0xa1; - args.NumGpc = 0x1; - args.L2CacheSize = 0x40000; - args.OnBoardVideoMemorySize = 0x0; - args.NumTpcPerGpc = 0x2; - args.BusType = 0x20; - args.BigPageSize = 0x20000; - args.CompressionPageSize = 0x20000; - args.PdeCoverageBitCount = 0x1b; - args.AvailableBigPageSizes = 0x30000; - args.GpcMask = 0x1; - args.SmArchSmVersion = 0x503; - args.SmArchSpaVersion = 0x503; - args.SmArchWarpCount = 0x80; - args.GpuVaBitCount = 0x28; - args.Reserved = 0x0; - args.Flags = 0x55; - args.TwodClass = 0x902d; - args.ThreedClass = 0xb197; - args.ComputeClass = 0xb1c0; - args.GpfifoClass = 0xb06f; - args.InlineToMemoryClass = 0xa140; - args.DmaCopyClass = 0xb0b5; - args.MaxFbpsCount = 0x1; - args.FbpEnMask = 0x0; - args.MaxLtcPerFbp = 0x2; - args.MaxLtsPerLtc = 0x1; - args.MaxTexPerTpc = 0x0; - args.MaxGpcCount = 0x1; - args.RopL2EnMask0 = 0x21d70; - args.RopL2EnMask1 = 0x0; - args.ChipName = 0x6230326d67; - args.GrCompbitStoreBaseHw = 0x0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetTpcMasks(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetTpcMasks args = MemoryHelper.Read(context.Memory, inputPosition); - - if (args.MaskBufferSize != 0) - { - args.TpcMask = 3; - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetActiveSlotMask(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetActiveSlotMask args = new NvGpuGpuGetActiveSlotMask(); - - args.Slot = 0x07; - args.Mask = 0x01; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int GetGpuTime(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - context.Memory.WriteInt64(outputPosition, GetPTimerNanoSeconds()); - - return NvResult.Success; - } - - private static long GetPTimerNanoSeconds() - { - double ticks = _pTimer.ElapsedTicks; - - return (long)(ticks * _ticksToNs) & 0xff_ffff_ffff_ffff; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs deleted file mode 100644 index 3ac9f92b..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuZcullGetCtxSize - { - public int Size; - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs deleted file mode 100644 index 4a7cafd5..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuZcullGetInfo - { - public int WidthAlignPixels; - public int HeightAlignPixels; - public int PixelSquaresByAliquots; - public int AliquotTotal; - public int RegionByteMultiplier; - public int RegionHeaderSize; - public int SubregionHeaderSize; - public int SubregionWidthAlignPixels; - public int SubregionHeightAlignPixels; - public int SubregionCount; - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs deleted file mode 100644 index 74d27a75..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - class NvChannel - { - public int Timeout; - public int SubmitTimeout; - public int Timeslice; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelPriority.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelPriority.cs deleted file mode 100644 index d41e7609..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelPriority.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - enum NvChannelPriority - { - Low = 50, - Medium = 100, - High = 150 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs deleted file mode 100644 index 44949597..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] - struct NvHostChannelCmdBuf - { - public int MemoryId; - public int Offset; - public int WordsCount; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs deleted file mode 100644 index 5c04e5d4..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] - struct NvHostChannelGetParamArg - { - public int Param; - public int Value; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs deleted file mode 100644 index fdfb3fa5..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs +++ /dev/null @@ -1,371 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Memory; -using Ryujinx.HLE.HOS.Kernel.Process; -using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; -using Ryujinx.HLE.HOS.Services.Nv.NvMap; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - class NvHostChannelIoctl - { - private static ConcurrentDictionary _channels; - - static NvHostChannelIoctl() - { - _channels = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x0001: return Submit (context); - case 0x0002: return GetSyncpoint (context); - case 0x0003: return GetWaitBase (context); - case 0x0007: return SetSubmitTimeout (context); - case 0x0009: return MapBuffer (context); - case 0x000a: return UnmapBuffer (context); - case 0x4714: return SetUserData (context); - case 0x4801: return SetNvMap (context); - case 0x4803: return SetTimeout (context); - case 0x4808: return SubmitGpfifo (context); - case 0x4809: return AllocObjCtx (context); - case 0x480b: return ZcullBind (context); - case 0x480c: return SetErrorNotifier (context); - case 0x480d: return SetPriority (context); - case 0x481a: return AllocGpfifoEx2 (context); - case 0x481b: return KickoffPbWithAttr(context); - case 0x481d: return SetTimeslice (context); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int Submit(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelSubmit args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - for (int index = 0; index < args.CmdBufsCount; index++) - { - long cmdBufOffset = inputPosition + 0x10 + index * 0xc; - - NvHostChannelCmdBuf cmdBuf = MemoryHelper.Read(context.Memory, cmdBufOffset); - - NvMapHandle map = NvMapIoctl.GetNvMap(context, cmdBuf.MemoryId); - - int[] cmdBufData = new int[cmdBuf.WordsCount]; - - for (int offset = 0; offset < cmdBufData.Length; offset++) - { - cmdBufData[offset] = context.Memory.ReadInt32(map.Address + cmdBuf.Offset + offset * 4); - } - - context.Device.Gpu.PushCommandBuffer(vmm, cmdBufData); - } - - // TODO: Relocation, waitchecks, etc. - - return NvResult.Success; - } - - private static int GetSyncpoint(ServiceCtx context) - { - // TODO - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelGetParamArg args = MemoryHelper.Read(context.Memory, inputPosition); - - args.Value = 0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetWaitBase(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelGetParamArg args = MemoryHelper.Read(context.Memory, inputPosition); - - args.Value = 0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int SetSubmitTimeout(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - - GetChannel(context).SubmitTimeout = context.Memory.ReadInt32(inputPosition); - - // TODO: Handle the timeout in the submit method. - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int MapBuffer(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - for (int index = 0; index < args.NumEntries; index++) - { - int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); - - NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); - - return NvResult.InvalidInput; - } - - lock (map) - { - if (map.DmaMapAddress == 0) - { - map.DmaMapAddress = vmm.MapLow(map.Address, map.Size); - } - - context.Memory.WriteInt32(outputPosition + 0xc + 4 + index * 8, (int)map.DmaMapAddress); - } - } - - return NvResult.Success; - } - - private static int UnmapBuffer(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - - NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - for (int index = 0; index < args.NumEntries; index++) - { - int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); - - NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); - - return NvResult.InvalidInput; - } - - lock (map) - { - if (map.DmaMapAddress != 0) - { - vmm.Free(map.DmaMapAddress, map.Size); - - map.DmaMapAddress = 0; - } - } - } - - return NvResult.Success; - } - - private static int SetUserData(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SetNvMap(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SetTimeout(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - - GetChannel(context).Timeout = context.Memory.ReadInt32(inputPosition); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SubmitGpfifo(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - for (int index = 0; index < args.NumEntries; index++) - { - long gpfifo = context.Memory.ReadInt64(inputPosition + 0x18 + index * 8); - - PushGpfifo(context, vmm, gpfifo); - } - - args.SyncptId = 0; - args.SyncptValue = 0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int AllocObjCtx(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int ZcullBind(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SetErrorNotifier(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SetPriority(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - - switch ((NvChannelPriority)context.Memory.ReadInt32(inputPosition)) - { - case NvChannelPriority.Low: - GetChannel(context).Timeslice = 1300; // Timeslice low priority in micro-seconds - break; - case NvChannelPriority.Medium: - GetChannel(context).Timeslice = 2600; // Timeslice medium priority in micro-seconds - break; - case NvChannelPriority.High: - GetChannel(context).Timeslice = 5200; // Timeslice high priority in micro-seconds - break; - default: - return NvResult.InvalidInput; - } - - Logger.PrintStub(LogClass.ServiceNv); - - // TODO: disable and preempt channel when GPU scheduler will be implemented. - - return NvResult.Success; - } - - private static int AllocGpfifoEx2(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int KickoffPbWithAttr(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - for (int index = 0; index < args.NumEntries; index++) - { - long gpfifo = context.Memory.ReadInt64(args.Address + index * 8); - - PushGpfifo(context, vmm, gpfifo); - } - - args.SyncptId = 0; - args.SyncptValue = 0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int SetTimeslice(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - int timeslice = context.Memory.ReadInt32(inputPosition); - - if (timeslice < 1000 || timeslice > 50000) - { - return NvResult.InvalidInput; - } - - GetChannel(context).Timeslice = timeslice; // in micro-seconds - - Logger.PrintStub(LogClass.ServiceNv); - - // TODO: disable and preempt channel when GPU scheduler will be implemented. - - return NvResult.Success; - } - - private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo) - { - context.Device.Gpu.Pusher.Push(vmm, gpfifo); - } - - public static NvChannel GetChannel(ServiceCtx context) - { - return _channels.GetOrAdd(context.Process, (key) => new NvChannel()); - } - - public static void UnloadProcess(KProcess process) - { - _channels.TryRemove(process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs deleted file mode 100644 index 1dfedf2d..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 4)] - struct NvHostChannelMapBuffer - { - public int NumEntries; - public int DataAddress; //Ignored by the driver. - public bool AttachHostChDas; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs deleted file mode 100644 index f776ad87..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] - struct NvHostChannelSubmit - { - public int CmdBufsCount; - public int RelocsCount; - public int SyncptIncrsCount; - public int WaitchecksCount; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs deleted file mode 100644 index edebcfeb..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - struct NvHostChannelSubmitGpfifo - { - public long Address; - public int NumEntries; - public int Flags; - public int SyncptId; - public int SyncptValue; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs deleted file mode 100644 index 2a84b677..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs +++ /dev/null @@ -1,399 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Kernel.Process; -using System; -using System.Collections.Concurrent; -using System.Text; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - class NvHostCtrlIoctl - { - private static ConcurrentDictionary _userCtxs; - - private static bool _isProductionMode = true; - - static NvHostCtrlIoctl() - { - _userCtxs = new ConcurrentDictionary(); - - if (Set.NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting)) - { - _isProductionMode = ((string)productionModeSetting) != "0"; // Default value is "" - } - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x0014: return SyncptRead (context); - case 0x0015: return SyncptIncr (context); - case 0x0016: return SyncptWait (context); - case 0x0019: return SyncptWaitEx (context); - case 0x001a: return SyncptReadMax (context); - case 0x001b: return GetConfig (context); - case 0x001d: return EventWait (context); - case 0x001e: return EventWaitAsync(context); - case 0x001f: return EventRegister (context); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int SyncptRead(ServiceCtx context) - { - return SyncptReadMinOrMax(context, max: false); - } - - private static int SyncptIncr(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - - int id = context.Memory.ReadInt32(inputPosition); - - if ((uint)id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - GetUserCtx(context).Syncpt.Increment(id); - - return NvResult.Success; - } - - private static int SyncptWait(ServiceCtx context) - { - return SyncptWait(context, extended: false); - } - - private static int SyncptWaitEx(ServiceCtx context) - { - return SyncptWait(context, extended: true); - } - - private static int SyncptReadMax(ServiceCtx context) - { - return SyncptReadMinOrMax(context, max: true); - } - - private static int GetConfig(ServiceCtx context) - { - if (!_isProductionMode) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - string domain = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0, 0x41); - string name = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0x41, 0x41); - - if (Set.NxSettings.Settings.TryGetValue($"{domain}!{name}", out object nvSetting)) - { - byte[] settingBuffer = new byte[0x101]; - - if (nvSetting is string stringValue) - { - if (stringValue.Length > 0x100) - { - Logger.PrintError(LogClass.ServiceNv, $"{domain}!{name} String value size is too big!"); - } - else - { - settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0"); - } - } - - if (nvSetting is int intValue) - { - settingBuffer = BitConverter.GetBytes(intValue); - } - else if (nvSetting is bool boolValue) - { - settingBuffer[0] = boolValue ? (byte)1 : (byte)0; - } - else - { - throw new NotImplementedException(nvSetting.GetType().Name); - } - - context.Memory.WriteBytes(outputPosition + 0x82, settingBuffer); - - Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {domain}!{name}"); - } - - return NvResult.Success; - } - - return NvResult.NotAvailableInProduction; - } - - private static int EventWait(ServiceCtx context) - { - return EventWait(context, async: false); - } - - private static int EventWaitAsync(ServiceCtx context) - { - return EventWait(context, async: true); - } - - private static int EventRegister(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - int eventId = context.Memory.ReadInt32(inputPosition); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int SyncptReadMinOrMax(ServiceCtx context, bool max) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptRead args = MemoryHelper.Read(context.Memory, inputPosition); - - if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - if (max) - { - args.Value = GetUserCtx(context).Syncpt.GetMax(args.Id); - } - else - { - args.Value = GetUserCtx(context).Syncpt.GetMin(args.Id); - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int SyncptWait(ServiceCtx context, bool extended) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptWait args = MemoryHelper.Read(context.Memory, inputPosition); - - NvHostSyncpt syncpt = GetUserCtx(context).Syncpt; - - if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - int result; - - if (syncpt.MinCompare(args.Id, args.Thresh)) - { - result = NvResult.Success; - } - else if (args.Timeout == 0) - { - result = NvResult.TryAgain; - } - else - { - Logger.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + args.Timeout + "ms..."); - - using (ManualResetEvent waitEvent = new ManualResetEvent(false)) - { - syncpt.AddWaiter(args.Thresh, waitEvent); - - // Note: Negative (> INT_MAX) timeouts aren't valid on .NET, - // in this case we just use the maximum timeout possible. - int timeout = args.Timeout; - - if (timeout < -1) - { - timeout = int.MaxValue; - } - - if (timeout == -1) - { - waitEvent.WaitOne(); - - result = NvResult.Success; - } - else if (waitEvent.WaitOne(timeout)) - { - result = NvResult.Success; - } - else - { - result = NvResult.TimedOut; - } - } - - Logger.PrintDebug(LogClass.ServiceNv, "Resuming..."); - } - - if (extended) - { - context.Memory.WriteInt32(outputPosition + 0xc, syncpt.GetMin(args.Id)); - } - - return result; - } - - private static int EventWait(ServiceCtx context, bool async) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptWaitEx args = MemoryHelper.Read(context.Memory, inputPosition); - - if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - void WriteArgs() - { - MemoryHelper.Write(context.Memory, outputPosition, args); - } - - NvHostSyncpt syncpt = GetUserCtx(context).Syncpt; - - if (syncpt.MinCompare(args.Id, args.Thresh)) - { - args.Value = syncpt.GetMin(args.Id); - - WriteArgs(); - - return NvResult.Success; - } - - if (!async) - { - args.Value = 0; - } - - if (args.Timeout == 0) - { - WriteArgs(); - - return NvResult.TryAgain; - } - - NvHostEvent Event; - - int result, eventIndex; - - if (async) - { - eventIndex = args.Value; - - if ((uint)eventIndex >= NvHostCtrlUserCtx.EventsCount) - { - return NvResult.InvalidInput; - } - - Event = GetUserCtx(context).Events[eventIndex]; - } - else - { - Event = GetFreeEvent(context, syncpt, args.Id, out eventIndex); - } - - if (Event != null && - (Event.State == NvHostEventState.Registered || - Event.State == NvHostEventState.Free)) - { - Event.Id = args.Id; - Event.Thresh = args.Thresh; - - Event.State = NvHostEventState.Waiting; - - if (!async) - { - args.Value = ((args.Id & 0xfff) << 16) | 0x10000000; - } - else - { - args.Value = args.Id << 4; - } - - args.Value |= eventIndex; - - result = NvResult.TryAgain; - } - else - { - result = NvResult.InvalidInput; - } - - WriteArgs(); - - return result; - } - - private static NvHostEvent GetFreeEvent( - ServiceCtx context, - NvHostSyncpt syncpt, - int id, - out int eventIndex) - { - NvHostEvent[] events = GetUserCtx(context).Events; - - eventIndex = NvHostCtrlUserCtx.EventsCount; - - int nullIndex = NvHostCtrlUserCtx.EventsCount; - - for (int index = 0; index < NvHostCtrlUserCtx.EventsCount; index++) - { - NvHostEvent Event = events[index]; - - if (Event != null) - { - if (Event.State == NvHostEventState.Registered || - Event.State == NvHostEventState.Free) - { - eventIndex = index; - - if (Event.Id == id) - { - return Event; - } - } - } - else if (nullIndex == NvHostCtrlUserCtx.EventsCount) - { - nullIndex = index; - } - } - - if (nullIndex < NvHostCtrlUserCtx.EventsCount) - { - eventIndex = nullIndex; - - return events[nullIndex] = new NvHostEvent(); - } - - if (eventIndex < NvHostCtrlUserCtx.EventsCount) - { - return events[eventIndex]; - } - - return null; - } - - public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx context) - { - return _userCtxs.GetOrAdd(context.Process, (key) => new NvHostCtrlUserCtx()); - } - - public static void UnloadProcess(KProcess process) - { - _userCtxs.TryRemove(process, out _); - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs deleted file mode 100644 index 275b6132..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptRead - { - public int Id; - public int Value; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs deleted file mode 100644 index 96e2f968..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptWait - { - public int Id; - public int Thresh; - public int Timeout; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs deleted file mode 100644 index 6aaa4718..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptWaitEx - { - public int Id; - public int Thresh; - public int Timeout; - public int Value; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs deleted file mode 100644 index fcb80836..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - class NvHostCtrlUserCtx - { - public const int LocksCount = 16; - public const int EventsCount = 64; - - public NvHostSyncpt Syncpt { get; private set; } - - public NvHostEvent[] Events { get; private set; } - - public NvHostCtrlUserCtx() - { - Syncpt = new NvHostSyncpt(); - - Events = new NvHostEvent[EventsCount]; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs deleted file mode 100644 index 71e5f1e6..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - class NvHostEvent - { - public int Id; - public int Thresh; - - public NvHostEventState State; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs deleted file mode 100644 index 61870c7f..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - enum NvHostEventState - { - Registered = 0, - Waiting = 1, - Busy = 2, - Free = 5 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs deleted file mode 100644 index d27f7c53..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl -{ - class NvHostSyncpt - { - public const int SyncptsCount = 192; - - private int[] _counterMin; - private int[] _counterMax; - - private long _eventMask; - - private ConcurrentDictionary _waiters; - - public NvHostSyncpt() - { - _counterMin = new int[SyncptsCount]; - _counterMax = new int[SyncptsCount]; - - _waiters = new ConcurrentDictionary(); - } - - public int GetMin(int id) - { - return _counterMin[id]; - } - - public int GetMax(int id) - { - return _counterMax[id]; - } - - public int Increment(int id) - { - if (((_eventMask >> id) & 1) != 0) - { - Interlocked.Increment(ref _counterMax[id]); - } - - return IncrementMin(id); - } - - public int IncrementMin(int id) - { - int value = Interlocked.Increment(ref _counterMin[id]); - - WakeUpWaiters(id, value); - - return value; - } - - public int IncrementMax(int id) - { - return Interlocked.Increment(ref _counterMax[id]); - } - - public void AddWaiter(int threshold, EventWaitHandle waitEvent) - { - if (!_waiters.TryAdd(waitEvent, threshold)) - { - throw new InvalidOperationException(); - } - } - - public bool RemoveWaiter(EventWaitHandle waitEvent) - { - return _waiters.TryRemove(waitEvent, out _); - } - - private void WakeUpWaiters(int id, int newValue) - { - foreach (KeyValuePair kv in _waiters) - { - if (MinCompare(id, newValue, _counterMax[id], kv.Value)) - { - kv.Key.Set(); - - _waiters.TryRemove(kv.Key, out _); - } - } - } - - public bool MinCompare(int id, int threshold) - { - return MinCompare(id, _counterMin[id], _counterMax[id], threshold); - } - - private bool MinCompare(int id, int min, int max, int threshold) - { - int minDiff = min - threshold; - int maxDiff = max - threshold; - - if (((_eventMask >> id) & 1) != 0) - { - return minDiff >= 0; - } - else - { - return (uint)maxDiff >= (uint)minDiff; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs deleted file mode 100644 index bc61baad..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapAlloc - { - public int Handle; - public int HeapMask; - public int Flags; - public int Align; - public long Kind; - public long Address; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs deleted file mode 100644 index dd4bff98..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapCreate - { - public int Size; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs deleted file mode 100644 index d946987e..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapFree - { - public int Handle; - public int Padding; - public long Address; - public int Size; - public int Flags; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs deleted file mode 100644 index e49257ea..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapFromId - { - public int Id; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs deleted file mode 100644 index 1f4f3290..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapGetId - { - public int Id; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs deleted file mode 100644 index 31bf8329..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - class NvMapHandle - { - public int Handle; - public int Id; - public int Size; - public int Align; - public int Kind; - public long Address; - public bool Allocated; - public long DmaMapAddress; - - private long _dupes; - - public NvMapHandle() - { - _dupes = 1; - } - - public NvMapHandle(int size) : this() - { - Size = size; - } - - public void IncrementRefCount() - { - Interlocked.Increment(ref _dupes); - } - - public long DecrementRefCount() - { - return Interlocked.Decrement(ref _dupes); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs deleted file mode 100644 index b360343c..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - enum NvMapHandleParam - { - Size = 1, - Align = 2, - Base = 3, - Heap = 4, - Kind = 5, - Compr = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs deleted file mode 100644 index d9c579a2..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs +++ /dev/null @@ -1,300 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Memory; -using Ryujinx.HLE.HOS.Kernel.Process; -using Ryujinx.HLE.Utilities; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - class NvMapIoctl - { - private const int FlagNotFreedYet = 1; - - private static ConcurrentDictionary _maps; - - static NvMapIoctl() - { - _maps = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x0101: return Create(context); - case 0x0103: return FromId(context); - case 0x0104: return Alloc (context); - case 0x0105: return Free (context); - case 0x0109: return Param (context); - case 0x010e: return GetId (context); - } - - Logger.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{cmd:x8}!"); - - return NvResult.NotSupported; - } - - private static int Create(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapCreate args = MemoryHelper.Read(context.Memory, inputPosition); - - if (args.Size == 0) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{args.Size:x8}!"); - - return NvResult.InvalidInput; - } - - int size = IntUtils.AlignUp(args.Size, NvGpuVmm.PageSize); - - args.Handle = AddNvMap(context, new NvMapHandle(size)); - - Logger.PrintInfo(LogClass.ServiceNv, $"Created map {args.Handle} with size 0x{size:x8}!"); - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int FromId(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapFromId args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Id); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - map.IncrementRefCount(); - - args.Handle = args.Id; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int Alloc(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapAlloc args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if ((args.Align & (args.Align - 1)) != 0) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{args.Align:x8}!"); - - return NvResult.InvalidInput; - } - - if ((uint)args.Align < NvGpuVmm.PageSize) - { - args.Align = NvGpuVmm.PageSize; - } - - int result = NvResult.Success; - - if (!map.Allocated) - { - map.Allocated = true; - - map.Align = args.Align; - map.Kind = (byte)args.Kind; - - int size = IntUtils.AlignUp(map.Size, NvGpuVmm.PageSize); - - long address = args.Address; - - if (address == 0) - { - // When the address is zero, we need to allocate - // our own backing memory for the NvMap. - // TODO: Is this allocation inside the transfer memory? - result = NvResult.OutOfMemory; - } - - if (result == NvResult.Success) - { - map.Size = size; - map.Address = address; - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int Free(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapFree args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if (map.DecrementRefCount() <= 0) - { - DeleteNvMap(context, args.Handle); - - Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {args.Handle}!"); - - args.Address = map.Address; - args.Flags = 0; - } - else - { - args.Address = 0; - args.Flags = FlagNotFreedYet; - } - - args.Size = map.Size; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int Param(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapParam args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - switch ((NvMapHandleParam)args.Param) - { - case NvMapHandleParam.Size: args.Result = map.Size; break; - case NvMapHandleParam.Align: args.Result = map.Align; break; - case NvMapHandleParam.Heap: args.Result = 0x40000000; break; - case NvMapHandleParam.Kind: args.Result = map.Kind; break; - case NvMapHandleParam.Compr: args.Result = 0; break; - - // Note: Base is not supported and returns an error. - // Any other value also returns an error. - default: return NvResult.InvalidInput; - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetId(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapGetId args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - args.Id = args.Handle; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int AddNvMap(ServiceCtx context, NvMapHandle map) - { - IdDictionary dict = _maps.GetOrAdd(context.Process, (key) => - { - IdDictionary newDict = new IdDictionary(); - - newDict.Add(0, new NvMapHandle()); - - return newDict; - }); - - return dict.Add(map); - } - - private static bool DeleteNvMap(ServiceCtx context, int handle) - { - if (_maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.Delete(handle) != null; - } - - return false; - } - - public static void InitializeNvMap(ServiceCtx context) - { - IdDictionary dict = _maps.GetOrAdd(context.Process, (key) =>new IdDictionary()); - - dict.Add(0, new NvMapHandle()); - } - - public static NvMapHandle GetNvMapWithFb(ServiceCtx context, int handle) - { - if (_maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.GetData(handle); - } - - return null; - } - - public static NvMapHandle GetNvMap(ServiceCtx context, int handle) - { - if (handle != 0 && _maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.GetData(handle); - } - - return null; - } - - public static void UnloadProcess(KProcess process) - { - _maps.TryRemove(process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs deleted file mode 100644 index b5213efe..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvMap -{ - struct NvMapParam - { - public int Handle; - public int Param; - public int Result; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs b/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs deleted file mode 100644 index 362a0450..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv -{ - static class NvResult - { - public const int NotAvailableInProduction = 196614; - public const int Success = 0; - public const int TryAgain = -11; - public const int OutOfMemory = -12; - public const int InvalidInput = -22; - public const int NotSupported = -25; - public const int Restart = -85; - public const int TimedOut = -110; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs new file mode 100644 index 00000000..b6c654e4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + class NvFd + { + public string Name { get; private set; } + + public NvFd(string name) + { + Name = name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs new file mode 100644 index 00000000..362a0450 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + static class NvResult + { + public const int NotAvailableInProduction = 196614; + public const int Success = 0; + public const int TryAgain = -11; + public const int OutOfMemory = -12; + public const int InvalidInput = -22; + public const int NotSupported = -25; + public const int Restart = -85; + public const int TimedOut = -110; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForSystemService.cs b/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForSystemService.cs new file mode 100644 index 00000000..52f74da9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForSystemService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Olsc +{ + [Service("olsc:s")] // 4.0.0+ + class IOlscServiceForSystemService : IpcService + { + public IOlscServiceForSystemService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ovln/IReceiverService.cs b/Ryujinx.HLE/HOS/Services/Ovln/IReceiverService.cs new file mode 100644 index 00000000..67b82e42 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ovln/IReceiverService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ovln +{ + [Service("ovln:rcv")] + class IReceiverService : IpcService + { + public IReceiverService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ovln/ISenderService.cs b/Ryujinx.HLE/HOS/Services/Ovln/ISenderService.cs new file mode 100644 index 00000000..70c860e1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ovln/ISenderService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ovln +{ + [Service("ovln:snd")] + class ISenderService : IpcService + { + public ISenderService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcie/ILogManager.cs b/Ryujinx.HLE/HOS/Services/Pcie/ILogManager.cs new file mode 100644 index 00000000..9c6387e1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcie/ILogManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcie +{ + [Service("pcie:log")] + class ILogManager : IpcService + { + public ILogManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcie/IManager.cs b/Ryujinx.HLE/HOS/Services/Pcie/IManager.cs new file mode 100644 index 00000000..f189dc8c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcie/IManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcie +{ + [Service("pcie")] + class IManager : IpcService + { + public IManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs deleted file mode 100644 index e9cc72c1..00000000 --- a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Pctl -{ - class IParentalControlService : IpcService - { - private bool _initialized = false; - - private bool _needInitialize; - - public IParentalControlService(bool needInitialize = true) - { - _needInitialize = needInitialize; - } - - [Command(1)] // 4.0.0+ - // Initialize() - public ResultCode Initialize(ServiceCtx context) - { - if (_needInitialize && !_initialized) - { - _initialized = true; - } - else - { - Logger.PrintWarning(LogClass.ServicePctl, "Service is already initialized!"); - } - - return ResultCode.Success; - } - - [Command(1001)] - // CheckFreeCommunicationPermission() - public ResultCode CheckFreeCommunicationPermission(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServicePctl); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs index b67543dd..678279f9 100644 --- a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs +++ b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory; + namespace Ryujinx.HLE.HOS.Services.Pctl { [Service("pctl")] diff --git a/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs new file mode 100644 index 00000000..0e7c8432 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs @@ -0,0 +1,41 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory +{ + class IParentalControlService : IpcService + { + private bool _initialized = false; + + private bool _needInitialize; + + public IParentalControlService(bool needInitialize = true) + { + _needInitialize = needInitialize; + } + + [Command(1)] // 4.0.0+ + // Initialize() + public ResultCode Initialize(ServiceCtx context) + { + if (_needInitialize && !_initialized) + { + _initialized = true; + } + else + { + Logger.PrintWarning(LogClass.ServicePctl, "Service is already initialized!"); + } + + return ResultCode.Success; + } + + [Command(1001)] + // CheckFreeCommunicationPermission() + public ResultCode CheckFreeCommunicationPermission(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServicePctl); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IBoardPowerControlManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IBoardPowerControlManager.cs new file mode 100644 index 00000000..7d0222d5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IBoardPowerControlManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv.Bpc +{ + [Service("bpc")] + class IBoardPowerControlManager : IpcService + { + public IBoardPowerControlManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IRtcManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IRtcManager.cs new file mode 100644 index 00000000..3b775da8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Bpc/IRtcManager.cs @@ -0,0 +1,34 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Pcv.Bpc +{ + [Service("bpc:r")] // 1.0.0 - 8.1.0 + class IRtcManager : IpcService + { + public IRtcManager(ServiceCtx context) { } + + [Command(0)] + // GetRtcTime() -> u64 + public ResultCode GetRtcTime(ServiceCtx context) + { + ResultCode result = GetExternalRtcValue(out ulong rtcValue); + + if (result == ResultCode.Success) + { + context.ResponseData.Write(rtcValue); + } + + return result; + } + + public static ResultCode GetExternalRtcValue(out ulong rtcValue) + { + // TODO: emulate MAX77620/MAX77812 RTC + DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + rtcValue = (ulong)(DateTime.Now.ToUniversalTime() - unixEpoch).TotalSeconds; + + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IArbitrationManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IArbitrationManager.cs new file mode 100644 index 00000000..6f1e5d25 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IArbitrationManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst +{ + [Service("clkrst:a")] // 8.0.0+ + class IArbitrationManager : IpcService + { + public IArbitrationManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs new file mode 100644 index 00000000..a82e8a94 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst +{ + [Service("clkrst")] // 8.0.0+ + [Service("clkrst:i")] // 8.0.0+ + class IClkrstManager : IpcService + { + public IClkrstManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs b/Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs new file mode 100644 index 00000000..0e74dc3e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv +{ + [Service("pcv")] + class IPcvService : IpcService + { + public IPcvService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Rgltr/IRegulatorManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Rgltr/IRegulatorManager.cs new file mode 100644 index 00000000..f7834777 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Rgltr/IRegulatorManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv.Rgltr +{ + [Service("rgltr")] // 8.0.0+ + class IRegulatorManager : IpcService + { + public IRegulatorManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Rtc/IUnknown1.cs b/Ryujinx.HLE/HOS/Services/Pcv/Rtc/IUnknown1.cs new file mode 100644 index 00000000..0f73f950 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pcv/Rtc/IUnknown1.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pcv.Rtc +{ + [Service("rtc")] // 8.0.0+ + class IUnknown1 : IpcService + { + public IUnknown1(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs deleted file mode 100644 index a5e3e52a..00000000 --- a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Ryujinx.HLE.HOS.Font; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using System; - -namespace Ryujinx.HLE.HOS.Services.Pl -{ - [Service("pl:u")] - class ISharedFontManager : IpcService - { - public ISharedFontManager(ServiceCtx context) { } - - [Command(0)] - // RequestLoad(u32) - public ResultCode RequestLoad(ServiceCtx context) - { - SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); - - // We don't need to do anything here because we do lazy initialization - // on SharedFontManager (the font is loaded when necessary). - return ResultCode.Success; - } - - [Command(1)] - // GetLoadState(u32) -> u32 - public ResultCode GetLoadState(ServiceCtx context) - { - SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); - - // 1 (true) indicates that the font is already loaded. - // All fonts are already loaded. - context.ResponseData.Write(1); - - return ResultCode.Success; - } - - [Command(2)] - // GetFontSize(u32) -> u32 - public ResultCode GetFontSize(ServiceCtx context) - { - SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); - - context.ResponseData.Write(context.Device.System.Font.GetFontSize(fontType)); - - return ResultCode.Success; - } - - [Command(3)] - // GetSharedMemoryAddressOffset(u32) -> u32 - public ResultCode GetSharedMemoryAddressOffset(ServiceCtx context) - { - SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); - - context.ResponseData.Write(context.Device.System.Font.GetSharedMemoryAddressOffset(fontType)); - - return ResultCode.Success; - } - - [Command(4)] - // GetSharedMemoryNativeHandle() -> handle - public ResultCode GetSharedMemoryNativeHandle(ServiceCtx context) - { - context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager); - - if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - [Command(5)] - // GetSharedFontInOrderOfPriority(bytes<8, 1>) -> (u8, u32, buffer, buffer, buffer) - public ResultCode GetSharedFontInOrderOfPriority(ServiceCtx context) - { - long languageCode = context.RequestData.ReadInt64(); - int loadedCount = 0; - - for (SharedFontType type = 0; type < SharedFontType.Count; type++) - { - int offset = (int)type * 4; - - if (!AddFontToOrderOfPriorityList(context, type, offset)) - { - break; - } - - loadedCount++; - } - - context.ResponseData.Write(loadedCount); - context.ResponseData.Write((int)SharedFontType.Count); - - return ResultCode.Success; - } - - private bool AddFontToOrderOfPriorityList(ServiceCtx context, SharedFontType fontType, int offset) - { - long typesPosition = context.Request.ReceiveBuff[0].Position; - long typesSize = context.Request.ReceiveBuff[0].Size; - - long offsetsPosition = context.Request.ReceiveBuff[1].Position; - long offsetsSize = context.Request.ReceiveBuff[1].Size; - - long fontSizeBufferPosition = context.Request.ReceiveBuff[2].Position; - long fontSizeBufferSize = context.Request.ReceiveBuff[2].Size; - - if ((uint)offset + 4 > (uint)typesSize || - (uint)offset + 4 > (uint)offsetsSize || - (uint)offset + 4 > (uint)fontSizeBufferSize) - { - return false; - } - - context.Memory.WriteInt32(typesPosition + offset, (int)fontType); - - context.Memory.WriteInt32(offsetsPosition + offset, context.Device.System.Font.GetSharedMemoryAddressOffset(fontType)); - - context.Memory.WriteInt32(fontSizeBufferPosition + offset, context.Device.System.Font.GetFontSize(fontType)); - - return true; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pm/IBootModeInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IBootModeInterface.cs new file mode 100644 index 00000000..45771db6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pm/IBootModeInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pm +{ + [Service("pm:bm")] + class IBootModeInterface : IpcService + { + public IBootModeInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs new file mode 100644 index 00000000..06c11943 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pm +{ + [Service("pm:dmnt")] + class IDebugMonitorInterface : IpcService + { + public IDebugMonitorInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs b/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs index 9fc9c115..94c027ab 100644 --- a/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs +++ b/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; namespace Ryujinx.HLE.HOS.Services.Prepo { [Service("prepo:a")] + [Service("prepo:a2")] [Service("prepo:u")] class IPrepoService : IpcService { diff --git a/Ryujinx.HLE/HOS/Services/Psc/IPmControl.cs b/Ryujinx.HLE/HOS/Services/Psc/IPmControl.cs new file mode 100644 index 00000000..3810c282 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Psc/IPmControl.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Psc +{ + [Service("psc:c")] + class IPmControl : IpcService + { + public IPmControl(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Psc/IPmService.cs b/Ryujinx.HLE/HOS/Services/Psc/IPmService.cs new file mode 100644 index 00000000..c8dfb32e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Psc/IPmService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Psc +{ + [Service("psc:m")] + class IPmService : IpcService + { + public IPmService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Psc/IPmUnknown.cs b/Ryujinx.HLE/HOS/Services/Psc/IPmUnknown.cs new file mode 100644 index 00000000..ef48fa41 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Psc/IPmUnknown.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Psc +{ + [Service("psc:l")] // 9.0.0+ + class IPmUnknown : IpcService + { + public IPmUnknown(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs b/Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs deleted file mode 100644 index 8dab66a1..00000000 --- a/Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Psm -{ - [Service("psm")] - class IPsmServer : IpcService - { - enum ChargerType - { - None, - ChargerOrDock, - UsbC - } - - public IPsmServer(ServiceCtx context) { } - - [Command(0)] - // GetBatteryChargePercentage() -> u32 - public static ResultCode GetBatteryChargePercentage(ServiceCtx context) - { - int chargePercentage = 100; - - context.ResponseData.Write(chargePercentage); - - Logger.PrintStub(LogClass.ServicePsm, new { chargePercentage }); - - return ResultCode.Success; - } - - [Command(1)] - // GetChargerType() -> u32 - public static ResultCode GetChargerType(ServiceCtx context) - { - ChargerType chargerType = ChargerType.ChargerOrDock; - - context.ResponseData.Write((int)chargerType); - - Logger.PrintStub(LogClass.ServicePsm, new { chargerType }); - - return ResultCode.Success; - } - - [Command(7)] - // OpenSession() -> IPsmSession - public ResultCode OpenSession(ServiceCtx context) - { - MakeObject(context, new IPsmSession(context.Device.System)); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs b/Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs deleted file mode 100644 index db4e0b75..00000000 --- a/Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Services.Psm -{ - class IPsmSession : IpcService - { - private KEvent _stateChangeEvent; - private int _stateChangeEventHandle; - - public IPsmSession(Horizon system) - { - _stateChangeEvent = new KEvent(system); - _stateChangeEventHandle = -1; - } - - [Command(0)] - // BindStateChangeEvent() -> KObject - public ResultCode BindStateChangeEvent(ServiceCtx context) - { - if (_stateChangeEventHandle == -1) - { - KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out int stateChangeEventHandle); - - if (resultCode != KernelResult.Success) - { - return (ResultCode)resultCode; - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle); - - Logger.PrintStub(LogClass.ServicePsm); - - return ResultCode.Success; - } - - [Command(1)] - // UnbindStateChangeEvent() - public ResultCode UnbindStateChangeEvent(ServiceCtx context) - { - if (_stateChangeEventHandle != -1) - { - context.Process.HandleTable.CloseHandle(_stateChangeEventHandle); - _stateChangeEventHandle = -1; - } - - Logger.PrintStub(LogClass.ServicePsm); - - return ResultCode.Success; - } - - [Command(2)] - // SetChargerTypeChangeEventEnabled(u8) - public ResultCode SetChargerTypeChangeEventEnabled(ServiceCtx context) - { - bool chargerTypeChangeEventEnabled = context.RequestData.ReadBoolean(); - - Logger.PrintStub(LogClass.ServicePsm, new { chargerTypeChangeEventEnabled }); - - return ResultCode.Success; - } - - [Command(3)] - // SetPowerSupplyChangeEventEnabled(u8) - public ResultCode SetPowerSupplyChangeEventEnabled(ServiceCtx context) - { - bool powerSupplyChangeEventEnabled = context.RequestData.ReadBoolean(); - - Logger.PrintStub(LogClass.ServicePsm, new { powerSupplyChangeEventEnabled }); - - return ResultCode.Success; - } - - [Command(4)] - // SetBatteryVoltageStateChangeEventEnabled(u8) - public ResultCode SetBatteryVoltageStateChangeEventEnabled(ServiceCtx context) - { - bool batteryVoltageStateChangeEventEnabled = context.RequestData.ReadBoolean(); - - Logger.PrintStub(LogClass.ServicePsm, new { batteryVoltageStateChangeEventEnabled }); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Fan/IManager.cs b/Ryujinx.HLE/HOS/Services/Ptm/Fan/IManager.cs new file mode 100644 index 00000000..e2fe2235 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Fan/IManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Fan +{ + [Service("fan")] + class IManager : IpcService + { + public IManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Fgm/IDebugger.cs b/Ryujinx.HLE/HOS/Services/Ptm/Fgm/IDebugger.cs new file mode 100644 index 00000000..a93f5283 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Fgm/IDebugger.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Fgm +{ + [Service("fgm:dbg")] // 9.0.0+ + class IDebugger : IpcService + { + public IDebugger(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Fgm/ISession.cs b/Ryujinx.HLE/HOS/Services/Ptm/Fgm/ISession.cs new file mode 100644 index 00000000..0e3f965b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Fgm/ISession.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Fgm +{ + [Service("fgm")] // 9.0.0+ + [Service("fgm:0")] // 9.0.0+ + [Service("fgm:9")] // 9.0.0+ + class ISession : IpcService + { + public ISession(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Pcm/IManager.cs b/Ryujinx.HLE/HOS/Services/Ptm/Pcm/IManager.cs new file mode 100644 index 00000000..0bec45fa --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Pcm/IManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Pcm +{ + [Service("pcm")] + class IManager : IpcService + { + public IManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmServer.cs b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmServer.cs new file mode 100644 index 00000000..9511e79d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmServer.cs @@ -0,0 +1,45 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Ptm.Psm +{ + [Service("psm")] + class IPsmServer : IpcService + { + public IPsmServer(ServiceCtx context) { } + + [Command(0)] + // GetBatteryChargePercentage() -> u32 + public static ResultCode GetBatteryChargePercentage(ServiceCtx context) + { + int chargePercentage = 100; + + context.ResponseData.Write(chargePercentage); + + Logger.PrintStub(LogClass.ServicePsm, new { chargePercentage }); + + return ResultCode.Success; + } + + [Command(1)] + // GetChargerType() -> u32 + public static ResultCode GetChargerType(ServiceCtx context) + { + ChargerType chargerType = ChargerType.ChargerOrDock; + + context.ResponseData.Write((int)chargerType); + + Logger.PrintStub(LogClass.ServicePsm, new { chargerType }); + + return ResultCode.Success; + } + + [Command(7)] + // OpenSession() -> IPsmSession + public ResultCode OpenSession(ServiceCtx context) + { + MakeObject(context, new IPsmSession(context.Device.System)); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs new file mode 100644 index 00000000..e41d6c37 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs @@ -0,0 +1,88 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Ptm.Psm +{ + class IPsmSession : IpcService + { + private KEvent _stateChangeEvent; + private int _stateChangeEventHandle; + + public IPsmSession(Horizon system) + { + _stateChangeEvent = new KEvent(system); + _stateChangeEventHandle = -1; + } + + [Command(0)] + // BindStateChangeEvent() -> KObject + public ResultCode BindStateChangeEvent(ServiceCtx context) + { + if (_stateChangeEventHandle == -1) + { + KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out int stateChangeEventHandle); + + if (resultCode != KernelResult.Success) + { + return (ResultCode)resultCode; + } + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle); + + Logger.PrintStub(LogClass.ServicePsm); + + return ResultCode.Success; + } + + [Command(1)] + // UnbindStateChangeEvent() + public ResultCode UnbindStateChangeEvent(ServiceCtx context) + { + if (_stateChangeEventHandle != -1) + { + context.Process.HandleTable.CloseHandle(_stateChangeEventHandle); + _stateChangeEventHandle = -1; + } + + Logger.PrintStub(LogClass.ServicePsm); + + return ResultCode.Success; + } + + [Command(2)] + // SetChargerTypeChangeEventEnabled(u8) + public ResultCode SetChargerTypeChangeEventEnabled(ServiceCtx context) + { + bool chargerTypeChangeEventEnabled = context.RequestData.ReadBoolean(); + + Logger.PrintStub(LogClass.ServicePsm, new { chargerTypeChangeEventEnabled }); + + return ResultCode.Success; + } + + [Command(3)] + // SetPowerSupplyChangeEventEnabled(u8) + public ResultCode SetPowerSupplyChangeEventEnabled(ServiceCtx context) + { + bool powerSupplyChangeEventEnabled = context.RequestData.ReadBoolean(); + + Logger.PrintStub(LogClass.ServicePsm, new { powerSupplyChangeEventEnabled }); + + return ResultCode.Success; + } + + [Command(4)] + // SetBatteryVoltageStateChangeEventEnabled(u8) + public ResultCode SetBatteryVoltageStateChangeEventEnabled(ServiceCtx context) + { + bool batteryVoltageStateChangeEventEnabled = context.RequestData.ReadBoolean(); + + Logger.PrintStub(LogClass.ServicePsm, new { batteryVoltageStateChangeEventEnabled }); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Psm/Types/ChargerType.cs b/Ryujinx.HLE/HOS/Services/Ptm/Psm/Types/ChargerType.cs new file mode 100644 index 00000000..3e239711 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Psm/Types/ChargerType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Psm +{ + enum ChargerType + { + None, + ChargerOrDock, + UsbC + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Tc/IManager.cs b/Ryujinx.HLE/HOS/Services/Ptm/Tc/IManager.cs new file mode 100644 index 00000000..1daa4f5e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Tc/IManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Tc +{ + [Service("tc")] + class IManager : IpcService + { + public IManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs b/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs new file mode 100644 index 00000000..f3b37d67 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Ptm.Ts +{ + [Service("ts")] + class IMeasurementServer : IpcService + { + public IMeasurementServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Avm/IAvmService.cs b/Ryujinx.HLE/HOS/Services/Sdb/Avm/IAvmService.cs new file mode 100644 index 00000000..d65c8bba --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Avm/IAvmService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Tcap +{ + [Service("avm")] // 6.0.0+ + class IAvmService : IpcService + { + public IAvmService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Mii/IImageDatabaseService.cs b/Ryujinx.HLE/HOS/Services/Sdb/Mii/IImageDatabaseService.cs new file mode 100644 index 00000000..b084714c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Mii/IImageDatabaseService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sdb.Mii +{ + [Service("miiimg")] // 5.0.0+ + class IImageDatabaseService : IpcService + { + public IImageDatabaseService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Mii/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Sdb/Mii/IStaticService.cs new file mode 100644 index 00000000..6c156d94 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Mii/IStaticService.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Sdb.Mii +{ + [Service("mii:e")] + [Service("mii:u")] + class IStaticService : IpcService + { + public IStaticService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pdm/INotifyService.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/INotifyService.cs new file mode 100644 index 00000000..5247a238 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/INotifyService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm +{ + [Service("pdm:ntfy")] + class INotifyService : IpcService + { + public INotifyService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pdm/IQueryService.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/IQueryService.cs new file mode 100644 index 00000000..61b26b8c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/IQueryService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm +{ + [Service("pdm:qry")] + class IQueryService : IpcService + { + public IQueryService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs new file mode 100644 index 00000000..4560d954 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs @@ -0,0 +1,128 @@ +using Ryujinx.HLE.HOS.Font; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using System; + +namespace Ryujinx.HLE.HOS.Services.Sdb.Pl +{ + [Service("pl:u")] + [Service("pl:s")] // 9.0.0+ + class ISharedFontManager : IpcService + { + public ISharedFontManager(ServiceCtx context) { } + + [Command(0)] + // RequestLoad(u32) + public ResultCode RequestLoad(ServiceCtx context) + { + SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); + + // We don't need to do anything here because we do lazy initialization + // on SharedFontManager (the font is loaded when necessary). + return ResultCode.Success; + } + + [Command(1)] + // GetLoadState(u32) -> u32 + public ResultCode GetLoadState(ServiceCtx context) + { + SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); + + // 1 (true) indicates that the font is already loaded. + // All fonts are already loaded. + context.ResponseData.Write(1); + + return ResultCode.Success; + } + + [Command(2)] + // GetFontSize(u32) -> u32 + public ResultCode GetFontSize(ServiceCtx context) + { + SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); + + context.ResponseData.Write(context.Device.System.Font.GetFontSize(fontType)); + + return ResultCode.Success; + } + + [Command(3)] + // GetSharedMemoryAddressOffset(u32) -> u32 + public ResultCode GetSharedMemoryAddressOffset(ServiceCtx context) + { + SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32(); + + context.ResponseData.Write(context.Device.System.Font.GetSharedMemoryAddressOffset(fontType)); + + return ResultCode.Success; + } + + [Command(4)] + // GetSharedMemoryNativeHandle() -> handle + public ResultCode GetSharedMemoryNativeHandle(ServiceCtx context) + { + context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager); + + if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + [Command(5)] + // GetSharedFontInOrderOfPriority(bytes<8, 1>) -> (u8, u32, buffer, buffer, buffer) + public ResultCode GetSharedFontInOrderOfPriority(ServiceCtx context) + { + long languageCode = context.RequestData.ReadInt64(); + int loadedCount = 0; + + for (SharedFontType type = 0; type < SharedFontType.Count; type++) + { + int offset = (int)type * 4; + + if (!AddFontToOrderOfPriorityList(context, type, offset)) + { + break; + } + + loadedCount++; + } + + context.ResponseData.Write(loadedCount); + context.ResponseData.Write((int)SharedFontType.Count); + + return ResultCode.Success; + } + + private bool AddFontToOrderOfPriorityList(ServiceCtx context, SharedFontType fontType, int offset) + { + long typesPosition = context.Request.ReceiveBuff[0].Position; + long typesSize = context.Request.ReceiveBuff[0].Size; + + long offsetsPosition = context.Request.ReceiveBuff[1].Position; + long offsetsSize = context.Request.ReceiveBuff[1].Size; + + long fontSizeBufferPosition = context.Request.ReceiveBuff[2].Position; + long fontSizeBufferSize = context.Request.ReceiveBuff[2].Size; + + if ((uint)offset + 4 > (uint)typesSize || + (uint)offset + 4 > (uint)offsetsSize || + (uint)offset + 4 > (uint)fontSizeBufferSize) + { + return false; + } + + context.Memory.WriteInt32(typesPosition + offset, (int)fontType); + + context.Memory.WriteInt32(offsetsPosition + offset, context.Device.System.Font.GetSharedMemoryAddressOffset(fontType)); + + context.Memory.WriteInt32(fontSizeBufferPosition + offset, context.Device.System.Font.GetFontSize(fontType)); + + return true; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs b/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs deleted file mode 100644 index 6fb923cc..00000000 --- a/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs +++ /dev/null @@ -1,109 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.SystemState; -using System; - -namespace Ryujinx.HLE.HOS.Services.Set -{ - [Service("set")] - class ISettingsServer : IpcService - { - public ISettingsServer(ServiceCtx context) { } - - [Command(0)] - // GetLanguageCode() -> nn::settings::LanguageCode - public ResultCode GetLanguageCode(ServiceCtx context) - { - context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode); - - return ResultCode.Success; - } - - [Command(1)] - // GetAvailableLanguageCodes() -> (u32, buffer) - public ResultCode GetAvailableLanguageCodes(ServiceCtx context) - { - return GetAvailableLanguagesCodesImpl( - context, - context.Request.RecvListBuff[0].Position, - context.Request.RecvListBuff[0].Size, - 0xF); - } - - [Command(2)] // 4.0.0+ - // MakeLanguageCode(nn::settings::Language language_index) -> nn::settings::LanguageCode - public ResultCode MakeLanguageCode(ServiceCtx context) - { - int languageIndex = context.RequestData.ReadInt32(); - - if ((uint)languageIndex >= (uint)SystemStateMgr.LanguageCodes.Length) - { - return ResultCode.LanguageOutOfRange; - } - - context.ResponseData.Write(SystemStateMgr.GetLanguageCode(languageIndex)); - - return ResultCode.Success; - } - - [Command(3)] - // GetAvailableLanguageCodeCount() -> u32 - public ResultCode GetAvailableLanguageCodeCount(ServiceCtx context) - { - context.ResponseData.Write(Math.Min(SystemStateMgr.LanguageCodes.Length, 0xF)); - - return ResultCode.Success; - } - - [Command(5)] - // GetAvailableLanguageCodes2() -> (u32, buffer) - public ResultCode GetAvailableLanguageCodes2(ServiceCtx context) - { - return GetAvailableLanguagesCodesImpl( - context, - context.Request.ReceiveBuff[0].Position, - context.Request.ReceiveBuff[0].Size, - SystemStateMgr.LanguageCodes.Length); - } - - [Command(6)] - // GetAvailableLanguageCodeCount2() -> u32 - public ResultCode GetAvailableLanguageCodeCount2(ServiceCtx context) - { - context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); - - return ResultCode.Success; - } - - [Command(8)] // 5.0.0+ - // GetQuestFlag() -> bool - public ResultCode GetQuestFlag(ServiceCtx context) - { - context.ResponseData.Write(false); - - Logger.PrintStub(LogClass.ServiceSet); - - return ResultCode.Success; - } - - public ResultCode GetAvailableLanguagesCodesImpl(ServiceCtx context, long position, long size, int maxSize) - { - int count = (int)(size / 8); - - if (count > maxSize) - { - count = maxSize; - } - - for (int index = 0; index < count; index++) - { - context.Memory.WriteInt64(position, SystemStateMgr.GetLanguageCode(index)); - - position += 8; - } - - context.ResponseData.Write(count); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs deleted file mode 100644 index 7a2f0672..00000000 --- a/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs +++ /dev/null @@ -1,198 +0,0 @@ -using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.SystemState; -using System; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Set -{ - [Service("set:sys")] - class ISystemSettingsServer : IpcService - { - public ISystemSettingsServer(ServiceCtx context) { } - - [Command(3)] - // GetFirmwareVersion() -> buffer - public ResultCode GetFirmwareVersion(ServiceCtx context) - { - return GetFirmwareVersion2(context); - } - - [Command(4)] - // GetFirmwareVersion2() -> buffer - public ResultCode GetFirmwareVersion2(ServiceCtx context) - { - long replyPos = context.Request.RecvListBuff[0].Position; - long replySize = context.Request.RecvListBuff[0].Size; - - byte[] firmwareData = GetFirmwareData(context.Device); - - if (firmwareData != null) - { - context.Memory.WriteBytes(replyPos, firmwareData); - - return ResultCode.Success; - } - - const byte majorFwVersion = 0x03; - const byte minorFwVersion = 0x00; - const byte microFwVersion = 0x00; - const byte unknown = 0x00; //Build? - - const int revisionNumber = 0x0A; - - const string platform = "NX"; - const string unknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47"; - const string version = "3.0.0"; - const string build = "NintendoSDK Firmware for NX 3.0.0-10.0"; - - // http://switchbrew.org/index.php?title=System_Version_Title - using (MemoryStream ms = new MemoryStream(0x100)) - { - BinaryWriter writer = new BinaryWriter(ms); - - writer.Write(majorFwVersion); - writer.Write(minorFwVersion); - writer.Write(microFwVersion); - writer.Write(unknown); - - writer.Write(revisionNumber); - - writer.Write(Encoding.ASCII.GetBytes(platform)); - - ms.Seek(0x28, SeekOrigin.Begin); - - writer.Write(Encoding.ASCII.GetBytes(unknownHex)); - - ms.Seek(0x68, SeekOrigin.Begin); - - writer.Write(Encoding.ASCII.GetBytes(version)); - - ms.Seek(0x80, SeekOrigin.Begin); - - writer.Write(Encoding.ASCII.GetBytes(build)); - - context.Memory.WriteBytes(replyPos, ms.ToArray()); - } - - return ResultCode.Success; - } - - [Command(23)] - // GetColorSetId() -> i32 - public ResultCode GetColorSetId(ServiceCtx context) - { - context.ResponseData.Write((int)context.Device.System.State.ThemeColor); - - return ResultCode.Success; - } - - [Command(24)] - // GetColorSetId() -> i32 - public ResultCode SetColorSetId(ServiceCtx context) - { - int colorSetId = context.RequestData.ReadInt32(); - - context.Device.System.State.ThemeColor = (ColorSet)colorSetId; - - return ResultCode.Success; - } - - [Command(38)] - // GetSettingsItemValue(buffer, buffer) -> (u64, buffer) - public ResultCode GetSettingsItemValue(ServiceCtx context) - { - long classPos = context.Request.PtrBuff[0].Position; - long classSize = context.Request.PtrBuff[0].Size; - - long namePos = context.Request.PtrBuff[1].Position; - long nameSize = context.Request.PtrBuff[1].Size; - - long replyPos = context.Request.ReceiveBuff[0].Position; - long replySize = context.Request.ReceiveBuff[0].Size; - - byte[] Class = context.Memory.ReadBytes(classPos, classSize); - byte[] name = context.Memory.ReadBytes(namePos, nameSize); - - string askedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(name).Trim('\0'); - - NxSettings.Settings.TryGetValue(askedSetting, out object nxSetting); - - if (nxSetting != null) - { - byte[] settingBuffer = new byte[replySize]; - - if (nxSetting is string stringValue) - { - if (stringValue.Length + 1 > replySize) - { - Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} String value size is too big!"); - } - else - { - settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0"); - } - } - - if (nxSetting is int intValue) - { - settingBuffer = BitConverter.GetBytes(intValue); - } - else if (nxSetting is bool boolValue) - { - settingBuffer[0] = boolValue ? (byte)1 : (byte)0; - } - else - { - throw new NotImplementedException(nxSetting.GetType().Name); - } - - context.Memory.WriteBytes(replyPos, settingBuffer); - - Logger.PrintDebug(LogClass.ServiceSet, $"{askedSetting} set value: {nxSetting} as {nxSetting.GetType()}"); - } - else - { - Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} not found!"); - } - - return ResultCode.Success; - } - - public byte[] GetFirmwareData(Switch device) - { - long titleId = 0x0100000000000809; - string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, ContentType.Data); - - if (string.IsNullOrWhiteSpace(contentPath)) - { - return null; - } - - string firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath); - - using(IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read)) - { - Nca firmwareContent = new Nca(device.System.KeySet, firmwareStorage); - - if (!firmwareContent.CanOpenSection(NcaSectionType.Data)) - { - return null; - } - - IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel); - - IFile firmwareFile = firmwareRomFs.OpenFile("/file", OpenMode.Read); - - byte[] data = new byte[firmwareFile.GetSize()]; - - firmwareFile.Read(data, 0); - - return data; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs b/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs deleted file mode 100644 index 46350743..00000000 --- a/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs +++ /dev/null @@ -1,1711 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Set -{ - static class NxSettings - { - // Generated automatically from a Switch 3.0 config file (Tid: 0100000000000818). - public static Dictionary Settings = new Dictionary - { - { "account!na_required_for_network_service", true }, - { "account.daemon!background_awaking_periodicity", 10800 }, - { "account.daemon!schedule_periodicity", 3600 }, - { "account.daemon!profile_sync_interval", 18000 }, - { "account.daemon!na_info_refresh_interval", 46800 }, - { "am.display!transition_layer_enabled", true }, - { "am.gpu!gpu_scheduling_enabled", true }, - { "am.gpu!gpu_scheduling_frame_time_us", 116666 }, - { "am.gpu!gpu_scheduling_fg_app_us", 116166 }, - { "am.gpu!gpu_scheduling_bg_app_us", 104500 }, - { "am.gpu!gpu_scheduling_oa_us", 500 }, - { "am.gpu!gpu_scheduling_fg_sa_us", 11666 }, - { "am.gpu!gpu_scheduling_bg_sa_us", 0 }, - { "am.gpu!gpu_scheduling_fg_la_us", 11666 }, - { "am.gpu!gpu_scheduling_partial_fg_la_us", 2000 }, - { "am.gpu!gpu_scheduling_bg_la_us", 0 }, - { "audio!audren_log_enabled", false }, - { "audio!audout_log_enabled", false }, - { "audio!audin_log_enabled", false }, - { "audio!hwopus_log_enabled", false }, - { "audio!adsp_log_enabled", false }, - { "audio!suspend_for_debugger_enabled", false }, - { "audio!uac_speaker_enabled", false }, - { "bgtc!enable_halfawake", 1 }, - { "bgtc!enable_battery_saver", 1 }, - { "bgtc!leaving_halfawake_margin", 3 }, - { "bgtc!battery_threshold_save", 20 }, - { "bgtc!battery_threshold_stop", 20 }, - { "bgtc!minimum_interval_normal", 1800 }, - { "bgtc!minimum_interval_save", 86400 }, - { "boot!force_maintenance", false }, - { "capsrv!screenshot_layerstack", "screenshot" }, - { "capsrv!enable_album_screenshot_filedata_verification", true }, - { "devmenu!enable_application_update", true }, - { "devmenu!enable_exhibition_mode", false }, - { "eclct!analytics_override", false }, - { "eclct!analytics_pollperiod", 86400 }, - { "err!applet_auto_close", false }, - { "friends!background_processing", true }, - { "htc!disconnection_emulation", false }, - { "idle!dim_level_percent_lcd", 10 }, - { "idle!dim_level_percent_tv", 70 }, - { "lbl!force_disable_als", false }, - { "lm!enable_sd_card_logging", false }, - { "lm!sd_card_log_output_directory", "NxBinLogs" }, - { "mii!is_db_test_mode_enabled", false }, - { "news!system_version", 2 }, - { "nfp!not_locked_tag", true }, - { "nfp!play_report", false }, - { "nifm!is_communication_control_enabled_for_test", false }, - { "nifm!connection_test_timeout", 45000 }, - { "nifm!apply_config_timeout", 30000 }, - { "nifm!ethernet_adapter_standby_time", 10000 }, - { "nim.install!prefer_delta_evenif_inefficient", false }, - { "nim.install!apply_delta_stress_storage", 0 }, - { "ns.notification!retry_interval", 60 }, - { "ns.notification!enable_network_update", true }, - { "ns.notification!enable_download_task_list", true }, - { "ns.notification!enable_version_list", true }, - { "ns.notification!enable_random_wait", true }, - { "ns.notification!debug_waiting_limit", 0 }, - { "ns.notification!enable_request_on_cold_boot", true }, - { "ns.sdcard!mount_sdcard", true }, - { "ns.sdcard!compare_sdcard", 0 }, - { "ns.gamecard!mount_gamecard_result_value", 0 }, - { "ns.gamecard!try_gamecard_access_result_value", 0 }, - { "nv!00008600", "" }, - { "nv!0007b25e", "" }, - { "nv!0083e1", "" }, - { "nv!01621887", "" }, - { "nv!03134743", "" }, - { "nv!0356afd0", "" }, - { "nv!0356afd1", "" }, - { "nv!0356afd2", "" }, - { "nv!0356afd3", "" }, - { "nv!094313", "" }, - { "nv!0x04dc09", "" }, - { "nv!0x111133", "" }, - { "nv!0x1aa483", "" }, - { "nv!0x1cb1cf", "" }, - { "nv!0x1cb1d0", "" }, - { "nv!0x1e3221", "" }, - { "nv!0x300fc8", "" }, - { "nv!0x301fc8", "" }, - { "nv!0x302fc8", "" }, - { "nv!0x3eec59", "" }, - { "nv!0x46b3ed", "" }, - { "nv!0x523dc0", "" }, - { "nv!0x523dc1", "" }, - { "nv!0x523dc2", "" }, - { "nv!0x523dc3", "" }, - { "nv!0x523dc4", "" }, - { "nv!0x523dc5", "" }, - { "nv!0x523dc6", "" }, - { "nv!0x523dd0", "" }, - { "nv!0x523dd1", "" }, - { "nv!0x523dd3", "" }, - { "nv!0x5344bb", "" }, - { "nv!0x555237", "" }, - { "nv!0x58a234", "" }, - { "nv!0x7b4428", "" }, - { "nv!0x923dc0", "" }, - { "nv!0x923dc1", "" }, - { "nv!0x923dc2", "" }, - { "nv!0x923dc3", "" }, - { "nv!0x923dc4", "" }, - { "nv!0x923dd3", "" }, - { "nv!0x9abdc5", "" }, - { "nv!0x9abdc6", "" }, - { "nv!0xaaa36c", "" }, - { "nv!0xb09da0", "" }, - { "nv!0xb09da1", "" }, - { "nv!0xb09da2", "" }, - { "nv!0xb09da3", "" }, - { "nv!0xb09da4", "" }, - { "nv!0xb09da5", "" }, - { "nv!0xb0b348", "" }, - { "nv!0xb0b349", "" }, - { "nv!0xbb558f", "" }, - { "nv!0xbd10fb", "" }, - { "nv!0xc32ad3", "" }, - { "nv!0xce2348", "" }, - { "nv!0xcfd81f", "" }, - { "nv!0xe0036b", "" }, - { "nv!0xe01f2d", "" }, - { "nv!0xe17212", "" }, - { "nv!0xeae966", "" }, - { "nv!0xed4f82", "" }, - { "nv!0xf12335", "" }, - { "nv!0xf12336", "" }, - { "nv!10261989", "" }, - { "nv!1042d483", "" }, - { "nv!10572898", "" }, - { "nv!115631", "" }, - { "nv!12950094", "" }, - { "nv!1314f311", "" }, - { "nv!1314f312", "" }, - { "nv!13279512", "" }, - { "nv!13813496", "" }, - { "nv!14507179", "" }, - { "nv!15694569", "" }, - { "nv!16936964", "" }, - { "nv!17aa230c", "" }, - { "nv!182054", "" }, - { "nv!18273275", "" }, - { "nv!18273276", "" }, - { "nv!1854d03b", "" }, - { "nv!18add00d", "" }, - { "nv!19156670", "" }, - { "nv!19286545", "" }, - { "nv!1a298e9f", "" }, - { "nv!1acf43fe", "" }, - { "nv!1bda43fe", "" }, - { "nv!1c3b92", "" }, - { "nv!21509920", "" }, - { "nv!215323457", "" }, - { "nv!2165ad", "" }, - { "nv!2165ae", "" }, - { "nv!21be9c", "" }, - { "nv!233264316", "" }, - { "nv!234557580", "" }, - { "nv!23cd0e", "" }, - { "nv!24189123", "" }, - { "nv!2443266", "" }, - { "nv!25025519", "" }, - { "nv!255e39", "" }, - { "nv!2583364", "" }, - { "nv!2888c1", "" }, - { "nv!28ca3e", "" }, - { "nv!29871243", "" }, - { "nv!2a1f64", "" }, - { "nv!2dc432", "" }, - { "nv!2de437", "" }, - { "nv!2f3bb89c", "" }, - { "nv!2fd652", "" }, - { "nv!3001ac", "" }, - { "nv!31298772", "" }, - { "nv!313233", "" }, - { "nv!31f7d603", "" }, - { "nv!320ce4", "" }, - { "nv!32153248", "" }, - { "nv!32153249", "" }, - { "nv!335bca", "" }, - { "nv!342abb", "" }, - { "nv!34dfe6", "" }, - { "nv!34dfe7", "" }, - { "nv!34dfe8", "" }, - { "nv!34dfe9", "" }, - { "nv!35201578", "" }, - { "nv!359278", "" }, - { "nv!37f53a", "" }, - { "nv!38144972", "" }, - { "nv!38542646", "" }, - { "nv!3b74c9", "" }, - { "nv!3c136f", "" }, - { "nv!3cf72823", "" }, - { "nv!3d7af029", "" }, - { "nv!3ff34782", "" }, - { "nv!4129618", "" }, - { "nv!4189fac3", "" }, - { "nv!420bd4", "" }, - { "nv!42a699", "" }, - { "nv!441369", "" }, - { "nv!4458713e", "" }, - { "nv!4554b6", "" }, - { "nv!457425", "" }, - { "nv!4603b207", "" }, - { "nv!46574957", "" }, - { "nv!46574958", "" }, - { "nv!46813529", "" }, - { "nv!46f1e13d", "" }, - { "nv!47534c43", "" }, - { "nv!48550336", "" }, - { "nv!48576893", "" }, - { "nv!48576894", "" }, - { "nv!4889ac02", "" }, - { "nv!49005740", "" }, - { "nv!49867584", "" }, - { "nv!49960973", "" }, - { "nv!4a5341", "" }, - { "nv!4f4e48", "" }, - { "nv!4f8a0a", "" }, - { "nv!50299698", "" }, - { "nv!50299699", "" }, - { "nv!50361291", "" }, - { "nv!5242ae", "" }, - { "nv!53d30c", "" }, - { "nv!56347a", "" }, - { "nv!563a95f1", "" }, - { "nv!573823", "" }, - { "nv!58027529", "" }, - { "nv!5d2d63", "" }, - { "nv!5f7e3b", "" }, - { "nv!60461793", "" }, - { "nv!60d355", "" }, - { "nv!616627aa", "" }, - { "nv!62317182", "" }, - { "nv!6253fa2e", "" }, - { "nv!64100768", "" }, - { "nv!64100769", "" }, - { "nv!64100770", "" }, - { "nv!647395", "" }, - { "nv!66543234", "" }, - { "nv!67674763", "" }, - { "nv!67739784", "" }, - { "nv!68fb9c", "" }, - { "nv!69801276", "" }, - { "nv!6af9fa2f", "" }, - { "nv!6af9fa3f", "" }, - { "nv!6af9fa4f", "" }, - { "nv!6bd8c7", "" }, - { "nv!6c7691", "" }, - { "nv!6d4296ce", "" }, - { "nv!6dd7e7", "" }, - { "nv!6dd7e8", "" }, - { "nv!6fe11ec1", "" }, - { "nv!716511763", "" }, - { "nv!72504593", "" }, - { "nv!73304097", "" }, - { "nv!73314098", "" }, - { "nv!74095213", "" }, - { "nv!74095213a", "" }, - { "nv!74095213b", "" }, - { "nv!74095214", "" }, - { "nv!748f9649", "" }, - { "nv!75494732", "" }, - { "nv!78452832", "" }, - { "nv!784561", "" }, - { "nv!78e16b9c", "" }, - { "nv!79251225", "" }, - { "nv!7c128b", "" }, - { "nv!7ccd93", "" }, - { "nv!7df8d1", "" }, - { "nv!800c2310", "" }, - { "nv!80546710", "" }, - { "nv!80772310", "" }, - { "nv!808ee280", "" }, - { "nv!81131154", "" }, - { "nv!81274457", "" }, - { "nv!8292291f", "" }, - { "nv!83498426", "" }, - { "nv!84993794", "" }, - { "nv!84995585", "" }, - { "nv!84a0a0", "" }, - { "nv!852142", "" }, - { "nv!85612309", "" }, - { "nv!85612310", "" }, - { "nv!85612311", "" }, - { "nv!85612312", "" }, - { "nv!8623ff27", "" }, - { "nv!87364952", "" }, - { "nv!87f6275666", "" }, - { "nv!886748", "" }, - { "nv!89894423", "" }, - { "nv!8ad8a75", "" }, - { "nv!8ad8ad00", "" }, - { "nv!8bb815", "" }, - { "nv!8bb817", "" }, - { "nv!8bb818", "" }, - { "nv!8bb819", "" }, - { "nv!8e640cd1", "" }, - { "nv!8f34971a", "" }, - { "nv!8f773984", "" }, - { "nv!8f7a7d", "" }, - { "nv!902486209", "" }, - { "nv!90482571", "" }, - { "nv!91214835", "" }, - { "nv!912848290", "" }, - { "nv!915e56", "" }, - { "nv!92179063", "" }, - { "nv!92179064", "" }, - { "nv!92179065", "" }, - { "nv!92179066", "" }, - { "nv!92350358", "" }, - { "nv!92809063", "" }, - { "nv!92809064", "" }, - { "nv!92809065", "" }, - { "nv!92809066", "" }, - { "nv!92920143", "" }, - { "nv!93a89b12", "" }, - { "nv!93a89c0b", "" }, - { "nv!94812574", "" }, - { "nv!95282304", "" }, - { "nv!95394027", "" }, - { "nv!959b1f", "" }, - { "nv!9638af", "" }, - { "nv!96fd59", "" }, - { "nv!97f6275666", "" }, - { "nv!97f6275667", "" }, - { "nv!97f6275668", "" }, - { "nv!97f6275669", "" }, - { "nv!97f627566a", "" }, - { "nv!97f627566b", "" }, - { "nv!97f627566d", "" }, - { "nv!97f627566e", "" }, - { "nv!97f627566f", "" }, - { "nv!97f6275670", "" }, - { "nv!97f6275671", "" }, - { "nv!97f727566e", "" }, - { "nv!98480775", "" }, - { "nv!98480776", "" }, - { "nv!98480777", "" }, - { "nv!992431", "" }, - { "nv!9aa29065", "" }, - { "nv!9af32c", "" }, - { "nv!9af32d", "" }, - { "nv!9af32e", "" }, - { "nv!9c108b71", "" }, - { "nv!9f279065", "" }, - { "nv!a01bc728", "" }, - { "nv!a13b46c80", "" }, - { "nv!a22eb0", "" }, - { "nv!a2fb451e", "" }, - { "nv!a3456abe", "" }, - { "nv!a7044887", "" }, - { "nv!a7149200", "" }, - { "nv!a766215670", "" }, - { "nv!aac_drc_boost", "" }, - { "nv!aac_drc_cut", "" }, - { "nv!aac_drc_enc_target_level", "" }, - { "nv!aac_drc_heavy", "" }, - { "nv!aac_drc_reference_level", "" }, - { "nv!aalinegamma", "" }, - { "nv!aalinetweaks", "" }, - { "nv!ab34ee01", "" }, - { "nv!ab34ee02", "" }, - { "nv!ab34ee03", "" }, - { "nv!ac0274", "" }, - { "nv!af73c63e", "" }, - { "nv!af73c63f", "" }, - { "nv!af9927", "" }, - { "nv!afoverride", "" }, - { "nv!allocdeviceevents", "" }, - { "nv!applicationkey", "" }, - { "nv!appreturnonlybasicglsltype", "" }, - { "nv!app_softimage", "" }, - { "nv!app_supportbits2", "" }, - { "nv!assumetextureismipmappedatcreation", "" }, - { "nv!b1fb0f01", "" }, - { "nv!b3edd5", "" }, - { "nv!b40d9e03d", "" }, - { "nv!b7f6275666", "" }, - { "nv!b812c1", "" }, - { "nv!ba14ba1a", "" }, - { "nv!ba14ba1b", "" }, - { "nv!bd7559", "" }, - { "nv!bd755a", "" }, - { "nv!bd755c", "" }, - { "nv!bd755d", "" }, - { "nv!be58bb", "" }, - { "nv!be92cb", "" }, - { "nv!beefcba3", "" }, - { "nv!beefcba4", "" }, - { "nv!c023777f", "" }, - { "nv!c09dc8", "" }, - { "nv!c0d340", "" }, - { "nv!c2ff374c", "" }, - { "nv!c5e9d7a3", "" }, - { "nv!c5e9d7a4", "" }, - { "nv!c5e9d7b4", "" }, - { "nv!c618f9", "" }, - { "nv!ca345840", "" }, - { "nv!cachedisable", "" }, - { "nv!cast.on", "" }, - { "nv!cde", "" }, - { "nv!channelpriorityoverride", "" }, - { "nv!cleardatastorevidmem", "" }, - { "nv!cmdbufmemoryspaceenables", "" }, - { "nv!cmdbufminwords", "" }, - { "nv!cmdbufsizewords", "" }, - { "nv!conformantblitframebufferscissor", "" }, - { "nv!conformantincompletetextures", "" }, - { "nv!copybuffermethod", "" }, - { "nv!cubemapaniso", "" }, - { "nv!cubemapfiltering", "" }, - { "nv!d0e9a4d7", "" }, - { "nv!d13733f12", "" }, - { "nv!d1b399", "" }, - { "nv!d2983c32", "" }, - { "nv!d2983c33", "" }, - { "nv!d2e71b", "" }, - { "nv!d377dc", "" }, - { "nv!d377dd", "" }, - { "nv!d489f4", "" }, - { "nv!d4bce1", "" }, - { "nv!d518cb", "" }, - { "nv!d518cd", "" }, - { "nv!d518ce", "" }, - { "nv!d518d0", "" }, - { "nv!d518d1", "" }, - { "nv!d518d2", "" }, - { "nv!d518d3", "" }, - { "nv!d518d4", "" }, - { "nv!d518d5", "" }, - { "nv!d59eda", "" }, - { "nv!d83cbd", "" }, - { "nv!d8e777", "" }, - { "nv!debug_level", "" }, - { "nv!debug_mask", "" }, - { "nv!debug_options", "" }, - { "nv!devshmpageableallocations", "" }, - { "nv!df1f9812", "" }, - { "nv!df783c", "" }, - { "nv!diagenable", "" }, - { "nv!disallowcemask", "" }, - { "nv!disallowz16", "" }, - { "nv!dlmemoryspaceenables", "" }, - { "nv!e0bfec", "" }, - { "nv!e433456d", "" }, - { "nv!e435563f", "" }, - { "nv!e4cd9c", "" }, - { "nv!e5c972", "" }, - { "nv!e639ef", "" }, - { "nv!e802af", "" }, - { "nv!eae964", "" }, - { "nv!earlytexturehwallocation", "" }, - { "nv!eb92a3", "" }, - { "nv!ebca56", "" }, - { "nv!enable-noaud", "" }, - { "nv!enable-noavs", "" }, - { "nv!enable-prof", "" }, - { "nv!enable-sxesmode", "" }, - { "nv!enable-ulld", "" }, - { "nv!expert_detail_level", "" }, - { "nv!expert_output_mask", "" }, - { "nv!expert_report_mask", "" }, - { "nv!extensionstringnvarch", "" }, - { "nv!extensionstringversion", "" }, - { "nv!f00f1938", "" }, - { "nv!f10736", "" }, - { "nv!f1846870", "" }, - { "nv!f33bc370", "" }, - { "nv!f392a874", "" }, - { "nv!f49ae8", "" }, - { "nv!fa345cce", "" }, - { "nv!fa35cc4", "" }, - { "nv!faa14a", "" }, - { "nv!faf8a723", "" }, - { "nv!fastgs", "" }, - { "nv!fbf4ac45", "" }, - { "nv!fbo_blit_ignore_srgb", "" }, - { "nv!fc64c7", "" }, - { "nv!ff54ec97", "" }, - { "nv!ff54ec98", "" }, - { "nv!forceexitprocessdetach", "" }, - { "nv!forcerequestedesversion", "" }, - { "nv!__gl_", "" }, - { "nv!__gl_00008600", "" }, - { "nv!__gl_0007b25e", "" }, - { "nv!__gl_0083e1", "" }, - { "nv!__gl_01621887", "" }, - { "nv!__gl_03134743", "" }, - { "nv!__gl_0356afd0", "" }, - { "nv!__gl_0356afd1", "" }, - { "nv!__gl_0356afd2", "" }, - { "nv!__gl_0356afd3", "" }, - { "nv!__gl_094313", "" }, - { "nv!__gl_0x04dc09", "" }, - { "nv!__gl_0x111133", "" }, - { "nv!__gl_0x1aa483", "" }, - { "nv!__gl_0x1cb1cf", "" }, - { "nv!__gl_0x1cb1d0", "" }, - { "nv!__gl_0x1e3221", "" }, - { "nv!__gl_0x300fc8", "" }, - { "nv!__gl_0x301fc8", "" }, - { "nv!__gl_0x302fc8", "" }, - { "nv!__gl_0x3eec59", "" }, - { "nv!__gl_0x46b3ed", "" }, - { "nv!__gl_0x523dc0", "" }, - { "nv!__gl_0x523dc1", "" }, - { "nv!__gl_0x523dc2", "" }, - { "nv!__gl_0x523dc3", "" }, - { "nv!__gl_0x523dc4", "" }, - { "nv!__gl_0x523dc5", "" }, - { "nv!__gl_0x523dc6", "" }, - { "nv!__gl_0x523dd0", "" }, - { "nv!__gl_0x523dd1", "" }, - { "nv!__gl_0x523dd3", "" }, - { "nv!__gl_0x5344bb", "" }, - { "nv!__gl_0x555237", "" }, - { "nv!__gl_0x58a234", "" }, - { "nv!__gl_0x7b4428", "" }, - { "nv!__gl_0x923dc0", "" }, - { "nv!__gl_0x923dc1", "" }, - { "nv!__gl_0x923dc2", "" }, - { "nv!__gl_0x923dc3", "" }, - { "nv!__gl_0x923dc4", "" }, - { "nv!__gl_0x923dd3", "" }, - { "nv!__gl_0x9abdc5", "" }, - { "nv!__gl_0x9abdc6", "" }, - { "nv!__gl_0xaaa36c", "" }, - { "nv!__gl_0xb09da0", "" }, - { "nv!__gl_0xb09da1", "" }, - { "nv!__gl_0xb09da2", "" }, - { "nv!__gl_0xb09da3", "" }, - { "nv!__gl_0xb09da4", "" }, - { "nv!__gl_0xb09da5", "" }, - { "nv!__gl_0xb0b348", "" }, - { "nv!__gl_0xb0b349", "" }, - { "nv!__gl_0xbb558f", "" }, - { "nv!__gl_0xbd10fb", "" }, - { "nv!__gl_0xc32ad3", "" }, - { "nv!__gl_0xce2348", "" }, - { "nv!__gl_0xcfd81f", "" }, - { "nv!__gl_0xe0036b", "" }, - { "nv!__gl_0xe01f2d", "" }, - { "nv!__gl_0xe17212", "" }, - { "nv!__gl_0xeae966", "" }, - { "nv!__gl_0xed4f82", "" }, - { "nv!__gl_0xf12335", "" }, - { "nv!__gl_0xf12336", "" }, - { "nv!__gl_10261989", "" }, - { "nv!__gl_1042d483", "" }, - { "nv!__gl_10572898", "" }, - { "nv!__gl_115631", "" }, - { "nv!__gl_12950094", "" }, - { "nv!__gl_1314f311", "" }, - { "nv!__gl_1314f312", "" }, - { "nv!__gl_13279512", "" }, - { "nv!__gl_13813496", "" }, - { "nv!__gl_14507179", "" }, - { "nv!__gl_15694569", "" }, - { "nv!__gl_16936964", "" }, - { "nv!__gl_17aa230c", "" }, - { "nv!__gl_182054", "" }, - { "nv!__gl_18273275", "" }, - { "nv!__gl_18273276", "" }, - { "nv!__gl_1854d03b", "" }, - { "nv!__gl_18add00d", "" }, - { "nv!__gl_19156670", "" }, - { "nv!__gl_19286545", "" }, - { "nv!__gl_1a298e9f", "" }, - { "nv!__gl_1acf43fe", "" }, - { "nv!__gl_1bda43fe", "" }, - { "nv!__gl_1c3b92", "" }, - { "nv!__gl_21509920", "" }, - { "nv!__gl_215323457", "" }, - { "nv!__gl_2165ad", "" }, - { "nv!__gl_2165ae", "" }, - { "nv!__gl_21be9c", "" }, - { "nv!__gl_233264316", "" }, - { "nv!__gl_234557580", "" }, - { "nv!__gl_23cd0e", "" }, - { "nv!__gl_24189123", "" }, - { "nv!__gl_2443266", "" }, - { "nv!__gl_25025519", "" }, - { "nv!__gl_255e39", "" }, - { "nv!__gl_2583364", "" }, - { "nv!__gl_2888c1", "" }, - { "nv!__gl_28ca3e", "" }, - { "nv!__gl_29871243", "" }, - { "nv!__gl_2a1f64", "" }, - { "nv!__gl_2dc432", "" }, - { "nv!__gl_2de437", "" }, - { "nv!__gl_2f3bb89c", "" }, - { "nv!__gl_2fd652", "" }, - { "nv!__gl_3001ac", "" }, - { "nv!__gl_31298772", "" }, - { "nv!__gl_313233", "" }, - { "nv!__gl_31f7d603", "" }, - { "nv!__gl_320ce4", "" }, - { "nv!__gl_32153248", "" }, - { "nv!__gl_32153249", "" }, - { "nv!__gl_335bca", "" }, - { "nv!__gl_342abb", "" }, - { "nv!__gl_34dfe6", "" }, - { "nv!__gl_34dfe7", "" }, - { "nv!__gl_34dfe8", "" }, - { "nv!__gl_34dfe9", "" }, - { "nv!__gl_35201578", "" }, - { "nv!__gl_359278", "" }, - { "nv!__gl_37f53a", "" }, - { "nv!__gl_38144972", "" }, - { "nv!__gl_38542646", "" }, - { "nv!__gl_3b74c9", "" }, - { "nv!__gl_3c136f", "" }, - { "nv!__gl_3cf72823", "" }, - { "nv!__gl_3d7af029", "" }, - { "nv!__gl_3ff34782", "" }, - { "nv!__gl_4129618", "" }, - { "nv!__gl_4189fac3", "" }, - { "nv!__gl_420bd4", "" }, - { "nv!__gl_42a699", "" }, - { "nv!__gl_441369", "" }, - { "nv!__gl_4458713e", "" }, - { "nv!__gl_4554b6", "" }, - { "nv!__gl_457425", "" }, - { "nv!__gl_4603b207", "" }, - { "nv!__gl_46574957", "" }, - { "nv!__gl_46574958", "" }, - { "nv!__gl_46813529", "" }, - { "nv!__gl_46f1e13d", "" }, - { "nv!__gl_47534c43", "" }, - { "nv!__gl_48550336", "" }, - { "nv!__gl_48576893", "" }, - { "nv!__gl_48576894", "" }, - { "nv!__gl_4889ac02", "" }, - { "nv!__gl_49005740", "" }, - { "nv!__gl_49867584", "" }, - { "nv!__gl_49960973", "" }, - { "nv!__gl_4a5341", "" }, - { "nv!__gl_4f4e48", "" }, - { "nv!__gl_4f8a0a", "" }, - { "nv!__gl_50299698", "" }, - { "nv!__gl_50299699", "" }, - { "nv!__gl_50361291", "" }, - { "nv!__gl_5242ae", "" }, - { "nv!__gl_53d30c", "" }, - { "nv!__gl_56347a", "" }, - { "nv!__gl_563a95f1", "" }, - { "nv!__gl_573823", "" }, - { "nv!__gl_58027529", "" }, - { "nv!__gl_5d2d63", "" }, - { "nv!__gl_5f7e3b", "" }, - { "nv!__gl_60461793", "" }, - { "nv!__gl_60d355", "" }, - { "nv!__gl_616627aa", "" }, - { "nv!__gl_62317182", "" }, - { "nv!__gl_6253fa2e", "" }, - { "nv!__gl_64100768", "" }, - { "nv!__gl_64100769", "" }, - { "nv!__gl_64100770", "" }, - { "nv!__gl_647395", "" }, - { "nv!__gl_66543234", "" }, - { "nv!__gl_67674763", "" }, - { "nv!__gl_67739784", "" }, - { "nv!__gl_68fb9c", "" }, - { "nv!__gl_69801276", "" }, - { "nv!__gl_6af9fa2f", "" }, - { "nv!__gl_6af9fa3f", "" }, - { "nv!__gl_6af9fa4f", "" }, - { "nv!__gl_6bd8c7", "" }, - { "nv!__gl_6c7691", "" }, - { "nv!__gl_6d4296ce", "" }, - { "nv!__gl_6dd7e7", "" }, - { "nv!__gl_6dd7e8", "" }, - { "nv!__gl_6fe11ec1", "" }, - { "nv!__gl_716511763", "" }, - { "nv!__gl_72504593", "" }, - { "nv!__gl_73304097", "" }, - { "nv!__gl_73314098", "" }, - { "nv!__gl_74095213", "" }, - { "nv!__gl_74095213a", "" }, - { "nv!__gl_74095213b", "" }, - { "nv!__gl_74095214", "" }, - { "nv!__gl_748f9649", "" }, - { "nv!__gl_75494732", "" }, - { "nv!__gl_78452832", "" }, - { "nv!__gl_784561", "" }, - { "nv!__gl_78e16b9c", "" }, - { "nv!__gl_79251225", "" }, - { "nv!__gl_7c128b", "" }, - { "nv!__gl_7ccd93", "" }, - { "nv!__gl_7df8d1", "" }, - { "nv!__gl_800c2310", "" }, - { "nv!__gl_80546710", "" }, - { "nv!__gl_80772310", "" }, - { "nv!__gl_808ee280", "" }, - { "nv!__gl_81131154", "" }, - { "nv!__gl_81274457", "" }, - { "nv!__gl_8292291f", "" }, - { "nv!__gl_83498426", "" }, - { "nv!__gl_84993794", "" }, - { "nv!__gl_84995585", "" }, - { "nv!__gl_84a0a0", "" }, - { "nv!__gl_852142", "" }, - { "nv!__gl_85612309", "" }, - { "nv!__gl_85612310", "" }, - { "nv!__gl_85612311", "" }, - { "nv!__gl_85612312", "" }, - { "nv!__gl_8623ff27", "" }, - { "nv!__gl_87364952", "" }, - { "nv!__gl_87f6275666", "" }, - { "nv!__gl_886748", "" }, - { "nv!__gl_89894423", "" }, - { "nv!__gl_8ad8a75", "" }, - { "nv!__gl_8ad8ad00", "" }, - { "nv!__gl_8bb815", "" }, - { "nv!__gl_8bb817", "" }, - { "nv!__gl_8bb818", "" }, - { "nv!__gl_8bb819", "" }, - { "nv!__gl_8e640cd1", "" }, - { "nv!__gl_8f34971a", "" }, - { "nv!__gl_8f773984", "" }, - { "nv!__gl_8f7a7d", "" }, - { "nv!__gl_902486209", "" }, - { "nv!__gl_90482571", "" }, - { "nv!__gl_91214835", "" }, - { "nv!__gl_912848290", "" }, - { "nv!__gl_915e56", "" }, - { "nv!__gl_92179063", "" }, - { "nv!__gl_92179064", "" }, - { "nv!__gl_92179065", "" }, - { "nv!__gl_92179066", "" }, - { "nv!__gl_92350358", "" }, - { "nv!__gl_92809063", "" }, - { "nv!__gl_92809064", "" }, - { "nv!__gl_92809065", "" }, - { "nv!__gl_92809066", "" }, - { "nv!__gl_92920143", "" }, - { "nv!__gl_93a89b12", "" }, - { "nv!__gl_93a89c0b", "" }, - { "nv!__gl_94812574", "" }, - { "nv!__gl_95282304", "" }, - { "nv!__gl_95394027", "" }, - { "nv!__gl_959b1f", "" }, - { "nv!__gl_9638af", "" }, - { "nv!__gl_96fd59", "" }, - { "nv!__gl_97f6275666", "" }, - { "nv!__gl_97f6275667", "" }, - { "nv!__gl_97f6275668", "" }, - { "nv!__gl_97f6275669", "" }, - { "nv!__gl_97f627566a", "" }, - { "nv!__gl_97f627566b", "" }, - { "nv!__gl_97f627566d", "" }, - { "nv!__gl_97f627566e", "" }, - { "nv!__gl_97f627566f", "" }, - { "nv!__gl_97f6275670", "" }, - { "nv!__gl_97f6275671", "" }, - { "nv!__gl_97f727566e", "" }, - { "nv!__gl_98480775", "" }, - { "nv!__gl_98480776", "" }, - { "nv!__gl_98480777", "" }, - { "nv!__gl_992431", "" }, - { "nv!__gl_9aa29065", "" }, - { "nv!__gl_9af32c", "" }, - { "nv!__gl_9af32d", "" }, - { "nv!__gl_9af32e", "" }, - { "nv!__gl_9c108b71", "" }, - { "nv!__gl_9f279065", "" }, - { "nv!__gl_a01bc728", "" }, - { "nv!__gl_a13b46c80", "" }, - { "nv!__gl_a22eb0", "" }, - { "nv!__gl_a2fb451e", "" }, - { "nv!__gl_a3456abe", "" }, - { "nv!__gl_a7044887", "" }, - { "nv!__gl_a7149200", "" }, - { "nv!__gl_a766215670", "" }, - { "nv!__gl_aalinegamma", "" }, - { "nv!__gl_aalinetweaks", "" }, - { "nv!__gl_ab34ee01", "" }, - { "nv!__gl_ab34ee02", "" }, - { "nv!__gl_ab34ee03", "" }, - { "nv!__gl_ac0274", "" }, - { "nv!__gl_af73c63e", "" }, - { "nv!__gl_af73c63f", "" }, - { "nv!__gl_af9927", "" }, - { "nv!__gl_afoverride", "" }, - { "nv!__gl_allocdeviceevents", "" }, - { "nv!__gl_applicationkey", "" }, - { "nv!__gl_appreturnonlybasicglsltype", "" }, - { "nv!__gl_app_softimage", "" }, - { "nv!__gl_app_supportbits2", "" }, - { "nv!__gl_assumetextureismipmappedatcreation", "" }, - { "nv!__gl_b1fb0f01", "" }, - { "nv!__gl_b3edd5", "" }, - { "nv!__gl_b40d9e03d", "" }, - { "nv!__gl_b7f6275666", "" }, - { "nv!__gl_b812c1", "" }, - { "nv!__gl_ba14ba1a", "" }, - { "nv!__gl_ba14ba1b", "" }, - { "nv!__gl_bd7559", "" }, - { "nv!__gl_bd755a", "" }, - { "nv!__gl_bd755c", "" }, - { "nv!__gl_bd755d", "" }, - { "nv!__gl_be58bb", "" }, - { "nv!__gl_be92cb", "" }, - { "nv!__gl_beefcba3", "" }, - { "nv!__gl_beefcba4", "" }, - { "nv!__gl_c023777f", "" }, - { "nv!__gl_c09dc8", "" }, - { "nv!__gl_c0d340", "" }, - { "nv!__gl_c2ff374c", "" }, - { "nv!__gl_c5e9d7a3", "" }, - { "nv!__gl_c5e9d7a4", "" }, - { "nv!__gl_c5e9d7b4", "" }, - { "nv!__gl_c618f9", "" }, - { "nv!__gl_ca345840", "" }, - { "nv!__gl_cachedisable", "" }, - { "nv!__gl_channelpriorityoverride", "" }, - { "nv!__gl_cleardatastorevidmem", "" }, - { "nv!__gl_cmdbufmemoryspaceenables", "" }, - { "nv!__gl_cmdbufminwords", "" }, - { "nv!__gl_cmdbufsizewords", "" }, - { "nv!__gl_conformantblitframebufferscissor", "" }, - { "nv!__gl_conformantincompletetextures", "" }, - { "nv!__gl_copybuffermethod", "" }, - { "nv!__gl_cubemapaniso", "" }, - { "nv!__gl_cubemapfiltering", "" }, - { "nv!__gl_d0e9a4d7", "" }, - { "nv!__gl_d13733f12", "" }, - { "nv!__gl_d1b399", "" }, - { "nv!__gl_d2983c32", "" }, - { "nv!__gl_d2983c33", "" }, - { "nv!__gl_d2e71b", "" }, - { "nv!__gl_d377dc", "" }, - { "nv!__gl_d377dd", "" }, - { "nv!__gl_d489f4", "" }, - { "nv!__gl_d4bce1", "" }, - { "nv!__gl_d518cb", "" }, - { "nv!__gl_d518cd", "" }, - { "nv!__gl_d518ce", "" }, - { "nv!__gl_d518d0", "" }, - { "nv!__gl_d518d1", "" }, - { "nv!__gl_d518d2", "" }, - { "nv!__gl_d518d3", "" }, - { "nv!__gl_d518d4", "" }, - { "nv!__gl_d518d5", "" }, - { "nv!__gl_d59eda", "" }, - { "nv!__gl_d83cbd", "" }, - { "nv!__gl_d8e777", "" }, - { "nv!__gl_debug_level", "" }, - { "nv!__gl_debug_mask", "" }, - { "nv!__gl_debug_options", "" }, - { "nv!__gl_devshmpageableallocations", "" }, - { "nv!__gl_df1f9812", "" }, - { "nv!__gl_df783c", "" }, - { "nv!__gl_diagenable", "" }, - { "nv!__gl_disallowcemask", "" }, - { "nv!__gl_disallowz16", "" }, - { "nv!__gl_dlmemoryspaceenables", "" }, - { "nv!__gl_e0bfec", "" }, - { "nv!__gl_e433456d", "" }, - { "nv!__gl_e435563f", "" }, - { "nv!__gl_e4cd9c", "" }, - { "nv!__gl_e5c972", "" }, - { "nv!__gl_e639ef", "" }, - { "nv!__gl_e802af", "" }, - { "nv!__gl_eae964", "" }, - { "nv!__gl_earlytexturehwallocation", "" }, - { "nv!__gl_eb92a3", "" }, - { "nv!__gl_ebca56", "" }, - { "nv!__gl_expert_detail_level", "" }, - { "nv!__gl_expert_output_mask", "" }, - { "nv!__gl_expert_report_mask", "" }, - { "nv!__gl_extensionstringnvarch", "" }, - { "nv!__gl_extensionstringversion", "" }, - { "nv!__gl_f00f1938", "" }, - { "nv!__gl_f10736", "" }, - { "nv!__gl_f1846870", "" }, - { "nv!__gl_f33bc370", "" }, - { "nv!__gl_f392a874", "" }, - { "nv!__gl_f49ae8", "" }, - { "nv!__gl_fa345cce", "" }, - { "nv!__gl_fa35cc4", "" }, - { "nv!__gl_faa14a", "" }, - { "nv!__gl_faf8a723", "" }, - { "nv!__gl_fastgs", "" }, - { "nv!__gl_fbf4ac45", "" }, - { "nv!__gl_fbo_blit_ignore_srgb", "" }, - { "nv!__gl_fc64c7", "" }, - { "nv!__gl_ff54ec97", "" }, - { "nv!__gl_ff54ec98", "" }, - { "nv!__gl_forceexitprocessdetach", "" }, - { "nv!__gl_forcerequestedesversion", "" }, - { "nv!__gl_glsynctovblank", "" }, - { "nv!__gl_gvitimeoutcontrol", "" }, - { "nv!__gl_hcctrl", "" }, - { "nv!__gl_hwstate_per_ctx", "" }, - { "nv!__gl_machinecachelimit", "" }, - { "nv!__gl_maxframesallowed", "" }, - { "nv!__gl_memmgrcachedalloclimit", "" }, - { "nv!__gl_memmgrcachedalloclimitratio", "" }, - { "nv!__gl_memmgrsysheapalloclimit", "" }, - { "nv!__gl_memmgrsysheapalloclimitratio", "" }, - { "nv!__gl_memmgrvidheapalloclimit", "" }, - { "nv!__gl_mosaic_clip_to_subdev", "" }, - { "nv!__gl_mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!__gl_mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!__gl_overlaymergeblittimerms", "" }, - { "nv!__gl_perfmon_mode", "" }, - { "nv!__gl_pixbar_mode", "" }, - { "nv!__gl_qualityenhancements", "" }, - { "nv!__gl_r27s18q28", "" }, - { "nv!__gl_r2d7c1d8", "" }, - { "nv!__gl_renderer", "" }, - { "nv!__gl_renderqualityflags", "" }, - { "nv!__gl_s3tcquality", "" }, - { "nv!__gl_shaderatomics", "" }, - { "nv!__gl_shadercacheinitsize", "" }, - { "nv!__gl_shader_disk_cache_path", "" }, - { "nv!__gl_shader_disk_cache_read_only", "" }, - { "nv!__gl_shaderobjects", "" }, - { "nv!__gl_shaderportabilitywarnings", "" }, - { "nv!__gl_shaderwarningsaserrors", "" }, - { "nv!__gl_skiptexturehostcopies", "" }, - { "nv!__glslc_debug_level", "" }, - { "nv!__glslc_debug_mask", "" }, - { "nv!__glslc_debug_options", "" }, - { "nv!__glslc_debug_filename", "" }, - { "nv!__gl_sli_dli_control", "" }, - { "nv!__gl_sparsetexture", "" }, - { "nv!__gl_spinlooptimeout", "" }, - { "nv!__gl_sync_to_vblank", "" }, - { "nv!glsynctovblank", "" }, - { "nv!__gl_sysheapreuseratio", "" }, - { "nv!__gl_sysmemtexturepromotion", "" }, - { "nv!__gl_targetflushcount", "" }, - { "nv!__gl_tearingfreeswappresent", "" }, - { "nv!__gl_texclampbehavior", "" }, - { "nv!__gl_texlodbias", "" }, - { "nv!__gl_texmemoryspaceenables", "" }, - { "nv!__gl_textureprecache", "" }, - { "nv!__gl_threadcontrol", "" }, - { "nv!__gl_threadcontrol2", "" }, - { "nv!__gl_usegvievents", "" }, - { "nv!__gl_vbomemoryspaceenables", "" }, - { "nv!__gl_vertexlimit", "" }, - { "nv!__gl_vidheapreuseratio", "" }, - { "nv!__gl_vpipe", "" }, - { "nv!__gl_vpipeformatbloatlimit", "" }, - { "nv!__gl_wglmessageboxonabort", "" }, - { "nv!__gl_writeinfolog", "" }, - { "nv!__gl_writeprogramobjectassembly", "" }, - { "nv!__gl_writeprogramobjectsource", "" }, - { "nv!__gl_xnvadapterpresent", "" }, - { "nv!__gl_yield", "" }, - { "nv!__gl_yieldfunction", "" }, - { "nv!__gl_yieldfunctionfast", "" }, - { "nv!__gl_yieldfunctionslow", "" }, - { "nv!__gl_yieldfunctionwaitfordcqueue", "" }, - { "nv!__gl_yieldfunctionwaitforframe", "" }, - { "nv!__gl_yieldfunctionwaitforgpu", "" }, - { "nv!__gl_zbctableaddhysteresis", "" }, - { "nv!gpu_debug_mode", "" }, - { "nv!gpu_stay_on", "" }, - { "nv!gpu_timeout_ms_max", "" }, - { "nv!gvitimeoutcontrol", "" }, - { "nv!hcctrl", "" }, - { "nv!hwstate_per_ctx", "" }, - { "nv!libandroid_enable_log", "" }, - { "nv!machinecachelimit", "" }, - { "nv!maxframesallowed", "" }, - { "nv!media.aac_51_output_enabled", "" }, - { "nv!memmgrcachedalloclimit", "" }, - { "nv!memmgrcachedalloclimitratio", "" }, - { "nv!memmgrsysheapalloclimit", "" }, - { "nv!memmgrsysheapalloclimitratio", "" }, - { "nv!memmgrvidheapalloclimit", "" }, - { "nv!mosaic_clip_to_subdev", "" }, - { "nv!mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!nvblit.dump", "" }, - { "nv!nvblit.profile", "" }, - { "nv!nvblit.twod", "" }, - { "nv!nvblit.vic", "" }, - { "nv!nvddk_vic_prevent_use", "" }, - { "nv!nv_decompression", "" }, - { "nv!nvdisp_bl_ctrl", "0" }, - { "nv!nvdisp_debug_mask", "" }, - { "nv!nvdisp_enable_ts", "0" }, - { "nv!nvhdcp_timeout_ms", "12000" }, - { "nv!nvhdcp_max_retries", "5" }, - { "nv!nv_emc_dvfs_test", "" }, - { "nv!nv_emc_init_rate_hz", "" }, - { "nv!nv_gmmu_va_page_split", "" }, - { "nv!nv_gmmu_va_range", "" }, - { "nv!nvhost_debug_mask", "" }, - { "nv!nvidia.hwc.dump_config", "" }, - { "nv!nvidia.hwc.dump_layerlist", "" }, - { "nv!nvidia.hwc.dump_windows", "" }, - { "nv!nvidia.hwc.enable_disp_trans", "" }, - { "nv!nvidia.hwc.ftrace_enable", "" }, - { "nv!nvidia.hwc.hdcp_enable", "" }, - { "nv!nvidia.hwc.hidden_window_mask0", "" }, - { "nv!nvidia.hwc.hidden_window_mask1", "" }, - { "nv!nvidia.hwc.immediate_modeset", "" }, - { "nv!nvidia.hwc.imp_enable", "" }, - { "nv!nvidia.hwc.no_egl", "" }, - { "nv!nvidia.hwc.no_scratchblit", "" }, - { "nv!nvidia.hwc.no_vic", "" }, - { "nv!nvidia.hwc.null_display", "" }, - { "nv!nvidia.hwc.scan_props", "" }, - { "nv!nvidia.hwc.swap_interval", "" }, - { "nv!nvidia.hwc.war_1515812", "0" }, - { "nv!nvmap_debug_mask", "" }, - { "nv!nv_memory_profiler", "" }, - { "nv!nvnflinger_enable_log", "" }, - { "nv!nvnflinger_flip_policy", "" }, - { "nv!nvnflinger_hotplug_autoswitch", "0" }, - { "nv!nvnflinger_prefer_primary_layer", "0" }, - { "nv!nvnflinger_service_priority", "" }, - { "nv!nvnflinger_service_threads", "" }, - { "nv!nvnflinger_swap_interval", "" }, - { "nv!nvnflinger_track_perf", "" }, - { "nv!nvnflinger_virtualdisplay_policy", "60hz" }, - { "nv!nvn_no_vsync_capability", false }, - { "nv!nvn_through_opengl", "" }, - { "nv!nv_pllcx_always_on", "" }, - { "nv!nv_pllcx_safe_div", "" }, - { "nv!nvrm_gpu_channel_interleave", "" }, - { "nv!nvrm_gpu_channel_priority", "" }, - { "nv!nvrm_gpu_channel_timeslice", "" }, - { "nv!nvrm_gpu_default_device_index", "" }, - { "nv!nvrm_gpu_dummy", "" }, - { "nv!nvrm_gpu_help", "" }, - { "nv!nvrm_gpu_nvgpu_disable", "" }, - { "nv!nvrm_gpu_nvgpu_do_nfa_partial_map", "" }, - { "nv!nvrm_gpu_nvgpu_ecc_overrides", "" }, - { "nv!nvrm_gpu_nvgpu_no_as_get_va_regions", "" }, - { "nv!nvrm_gpu_nvgpu_no_channel_abort", "" }, - { "nv!nvrm_gpu_nvgpu_no_cyclestats", "" }, - { "nv!nvrm_gpu_nvgpu_no_fixed", "" }, - { "nv!nvrm_gpu_nvgpu_no_gpu_characteristics", "" }, - { "nv!nvrm_gpu_nvgpu_no_ioctl_mutex", "" }, - { "nv!nvrm_gpu_nvgpu_no_map_buffer_ex", "" }, - { "nv!nvrm_gpu_nvgpu_no_robustness", "" }, - { "nv!nvrm_gpu_nvgpu_no_sparse", "" }, - { "nv!nvrm_gpu_nvgpu_no_syncpoints", "" }, - { "nv!nvrm_gpu_nvgpu_no_tsg", "" }, - { "nv!nvrm_gpu_nvgpu_no_zbc", "" }, - { "nv!nvrm_gpu_nvgpu_no_zcull", "" }, - { "nv!nvrm_gpu_nvgpu_wrap_channels_in_tsgs", "" }, - { "nv!nvrm_gpu_prevent_use", "" }, - { "nv!nvrm_gpu_trace", "" }, - { "nv!nvsched_debug_mask", "" }, - { "nv!nvsched_force_enable", "" }, - { "nv!nvsched_force_log", "" }, - { "nv!nv_usb_plls_hw_ctrl", "" }, - { "nv!nv_winsys", "" }, - { "nv!nvwsi_dump", "" }, - { "nv!nvwsi_fill", "" }, - { "nv!ogl_", "" }, - { "nv!ogl_0356afd0", "" }, - { "nv!ogl_0356afd1", "" }, - { "nv!ogl_0356afd2", "" }, - { "nv!ogl_0356afd3", "" }, - { "nv!ogl_0x923dc0", "" }, - { "nv!ogl_0x923dc1", "" }, - { "nv!ogl_0x923dc2", "" }, - { "nv!ogl_0x923dc3", "" }, - { "nv!ogl_0x923dc4", "" }, - { "nv!ogl_0x923dd3", "" }, - { "nv!ogl_0x9abdc5", "" }, - { "nv!ogl_0x9abdc6", "" }, - { "nv!ogl_0xbd10fb", "" }, - { "nv!ogl_0xce2348", "" }, - { "nv!ogl_10261989", "" }, - { "nv!ogl_1042d483", "" }, - { "nv!ogl_10572898", "" }, - { "nv!ogl_115631", "" }, - { "nv!ogl_12950094", "" }, - { "nv!ogl_1314f311", "" }, - { "nv!ogl_1314f312", "" }, - { "nv!ogl_13279512", "" }, - { "nv!ogl_13813496", "" }, - { "nv!ogl_14507179", "" }, - { "nv!ogl_15694569", "" }, - { "nv!ogl_16936964", "" }, - { "nv!ogl_17aa230c", "" }, - { "nv!ogl_182054", "" }, - { "nv!ogl_18273275", "" }, - { "nv!ogl_18273276", "" }, - { "nv!ogl_1854d03b", "" }, - { "nv!ogl_18add00d", "" }, - { "nv!ogl_19156670", "" }, - { "nv!ogl_19286545", "" }, - { "nv!ogl_1a298e9f", "" }, - { "nv!ogl_1acf43fe", "" }, - { "nv!ogl_1bda43fe", "" }, - { "nv!ogl_1c3b92", "" }, - { "nv!ogl_21509920", "" }, - { "nv!ogl_215323457", "" }, - { "nv!ogl_2165ad", "" }, - { "nv!ogl_2165ae", "" }, - { "nv!ogl_21be9c", "" }, - { "nv!ogl_233264316", "" }, - { "nv!ogl_234557580", "" }, - { "nv!ogl_23cd0e", "" }, - { "nv!ogl_24189123", "" }, - { "nv!ogl_2443266", "" }, - { "nv!ogl_25025519", "" }, - { "nv!ogl_255e39", "" }, - { "nv!ogl_2583364", "" }, - { "nv!ogl_2888c1", "" }, - { "nv!ogl_28ca3e", "" }, - { "nv!ogl_29871243", "" }, - { "nv!ogl_2a1f64", "" }, - { "nv!ogl_2dc432", "" }, - { "nv!ogl_2de437", "" }, - { "nv!ogl_2f3bb89c", "" }, - { "nv!ogl_2fd652", "" }, - { "nv!ogl_3001ac", "" }, - { "nv!ogl_31298772", "" }, - { "nv!ogl_313233", "" }, - { "nv!ogl_31f7d603", "" }, - { "nv!ogl_320ce4", "" }, - { "nv!ogl_32153248", "" }, - { "nv!ogl_32153249", "" }, - { "nv!ogl_335bca", "" }, - { "nv!ogl_342abb", "" }, - { "nv!ogl_34dfe6", "" }, - { "nv!ogl_34dfe7", "" }, - { "nv!ogl_34dfe8", "" }, - { "nv!ogl_34dfe9", "" }, - { "nv!ogl_35201578", "" }, - { "nv!ogl_359278", "" }, - { "nv!ogl_37f53a", "" }, - { "nv!ogl_38144972", "" }, - { "nv!ogl_38542646", "" }, - { "nv!ogl_3b74c9", "" }, - { "nv!ogl_3c136f", "" }, - { "nv!ogl_3cf72823", "" }, - { "nv!ogl_3d7af029", "" }, - { "nv!ogl_3ff34782", "" }, - { "nv!ogl_4129618", "" }, - { "nv!ogl_4189fac3", "" }, - { "nv!ogl_420bd4", "" }, - { "nv!ogl_42a699", "" }, - { "nv!ogl_441369", "" }, - { "nv!ogl_4458713e", "" }, - { "nv!ogl_4554b6", "" }, - { "nv!ogl_457425", "" }, - { "nv!ogl_4603b207", "" }, - { "nv!ogl_46574957", "" }, - { "nv!ogl_46574958", "" }, - { "nv!ogl_46813529", "" }, - { "nv!ogl_46f1e13d", "" }, - { "nv!ogl_47534c43", "" }, - { "nv!ogl_48550336", "" }, - { "nv!ogl_48576893", "" }, - { "nv!ogl_48576894", "" }, - { "nv!ogl_4889ac02", "" }, - { "nv!ogl_49005740", "" }, - { "nv!ogl_49867584", "" }, - { "nv!ogl_49960973", "" }, - { "nv!ogl_4a5341", "" }, - { "nv!ogl_4f4e48", "" }, - { "nv!ogl_4f8a0a", "" }, - { "nv!ogl_50299698", "" }, - { "nv!ogl_50299699", "" }, - { "nv!ogl_50361291", "" }, - { "nv!ogl_5242ae", "" }, - { "nv!ogl_53d30c", "" }, - { "nv!ogl_56347a", "" }, - { "nv!ogl_563a95f1", "" }, - { "nv!ogl_573823", "" }, - { "nv!ogl_58027529", "" }, - { "nv!ogl_5d2d63", "" }, - { "nv!ogl_5f7e3b", "" }, - { "nv!ogl_60461793", "" }, - { "nv!ogl_60d355", "" }, - { "nv!ogl_616627aa", "" }, - { "nv!ogl_62317182", "" }, - { "nv!ogl_6253fa2e", "" }, - { "nv!ogl_64100768", "" }, - { "nv!ogl_64100769", "" }, - { "nv!ogl_64100770", "" }, - { "nv!ogl_647395", "" }, - { "nv!ogl_66543234", "" }, - { "nv!ogl_67674763", "" }, - { "nv!ogl_67739784", "" }, - { "nv!ogl_68fb9c", "" }, - { "nv!ogl_69801276", "" }, - { "nv!ogl_6af9fa2f", "" }, - { "nv!ogl_6af9fa3f", "" }, - { "nv!ogl_6af9fa4f", "" }, - { "nv!ogl_6bd8c7", "" }, - { "nv!ogl_6c7691", "" }, - { "nv!ogl_6d4296ce", "" }, - { "nv!ogl_6dd7e7", "" }, - { "nv!ogl_6dd7e8", "" }, - { "nv!ogl_6fe11ec1", "" }, - { "nv!ogl_716511763", "" }, - { "nv!ogl_72504593", "" }, - { "nv!ogl_73304097", "" }, - { "nv!ogl_73314098", "" }, - { "nv!ogl_74095213", "" }, - { "nv!ogl_74095213a", "" }, - { "nv!ogl_74095213b", "" }, - { "nv!ogl_74095214", "" }, - { "nv!ogl_748f9649", "" }, - { "nv!ogl_75494732", "" }, - { "nv!ogl_78452832", "" }, - { "nv!ogl_784561", "" }, - { "nv!ogl_78e16b9c", "" }, - { "nv!ogl_79251225", "" }, - { "nv!ogl_7c128b", "" }, - { "nv!ogl_7ccd93", "" }, - { "nv!ogl_7df8d1", "" }, - { "nv!ogl_800c2310", "" }, - { "nv!ogl_80546710", "" }, - { "nv!ogl_80772310", "" }, - { "nv!ogl_808ee280", "" }, - { "nv!ogl_81131154", "" }, - { "nv!ogl_81274457", "" }, - { "nv!ogl_8292291f", "" }, - { "nv!ogl_83498426", "" }, - { "nv!ogl_84993794", "" }, - { "nv!ogl_84995585", "" }, - { "nv!ogl_84a0a0", "" }, - { "nv!ogl_852142", "" }, - { "nv!ogl_85612309", "" }, - { "nv!ogl_85612310", "" }, - { "nv!ogl_85612311", "" }, - { "nv!ogl_85612312", "" }, - { "nv!ogl_8623ff27", "" }, - { "nv!ogl_87364952", "" }, - { "nv!ogl_87f6275666", "" }, - { "nv!ogl_886748", "" }, - { "nv!ogl_89894423", "" }, - { "nv!ogl_8ad8a75", "" }, - { "nv!ogl_8ad8ad00", "" }, - { "nv!ogl_8bb815", "" }, - { "nv!ogl_8bb817", "" }, - { "nv!ogl_8bb818", "" }, - { "nv!ogl_8bb819", "" }, - { "nv!ogl_8e640cd1", "" }, - { "nv!ogl_8f34971a", "" }, - { "nv!ogl_8f773984", "" }, - { "nv!ogl_8f7a7d", "" }, - { "nv!ogl_902486209", "" }, - { "nv!ogl_90482571", "" }, - { "nv!ogl_91214835", "" }, - { "nv!ogl_912848290", "" }, - { "nv!ogl_915e56", "" }, - { "nv!ogl_92179063", "" }, - { "nv!ogl_92179064", "" }, - { "nv!ogl_92179065", "" }, - { "nv!ogl_92179066", "" }, - { "nv!ogl_92350358", "" }, - { "nv!ogl_92809063", "" }, - { "nv!ogl_92809064", "" }, - { "nv!ogl_92809065", "" }, - { "nv!ogl_92809066", "" }, - { "nv!ogl_92920143", "" }, - { "nv!ogl_93a89b12", "" }, - { "nv!ogl_93a89c0b", "" }, - { "nv!ogl_94812574", "" }, - { "nv!ogl_95282304", "" }, - { "nv!ogl_95394027", "" }, - { "nv!ogl_959b1f", "" }, - { "nv!ogl_9638af", "" }, - { "nv!ogl_96fd59", "" }, - { "nv!ogl_97f6275666", "" }, - { "nv!ogl_97f6275667", "" }, - { "nv!ogl_97f6275668", "" }, - { "nv!ogl_97f6275669", "" }, - { "nv!ogl_97f627566a", "" }, - { "nv!ogl_97f627566b", "" }, - { "nv!ogl_97f627566d", "" }, - { "nv!ogl_97f627566e", "" }, - { "nv!ogl_97f627566f", "" }, - { "nv!ogl_97f6275670", "" }, - { "nv!ogl_97f6275671", "" }, - { "nv!ogl_97f727566e", "" }, - { "nv!ogl_98480775", "" }, - { "nv!ogl_98480776", "" }, - { "nv!ogl_98480777", "" }, - { "nv!ogl_992431", "" }, - { "nv!ogl_9aa29065", "" }, - { "nv!ogl_9af32c", "" }, - { "nv!ogl_9af32d", "" }, - { "nv!ogl_9af32e", "" }, - { "nv!ogl_9c108b71", "" }, - { "nv!ogl_9f279065", "" }, - { "nv!ogl_a01bc728", "" }, - { "nv!ogl_a13b46c80", "" }, - { "nv!ogl_a22eb0", "" }, - { "nv!ogl_a2fb451e", "" }, - { "nv!ogl_a3456abe", "" }, - { "nv!ogl_a7044887", "" }, - { "nv!ogl_a7149200", "" }, - { "nv!ogl_a766215670", "" }, - { "nv!ogl_aalinegamma", "" }, - { "nv!ogl_aalinetweaks", "" }, - { "nv!ogl_ab34ee01", "" }, - { "nv!ogl_ab34ee02", "" }, - { "nv!ogl_ab34ee03", "" }, - { "nv!ogl_ac0274", "" }, - { "nv!ogl_af73c63e", "" }, - { "nv!ogl_af73c63f", "" }, - { "nv!ogl_af9927", "" }, - { "nv!ogl_afoverride", "" }, - { "nv!ogl_allocdeviceevents", "" }, - { "nv!ogl_applicationkey", "" }, - { "nv!ogl_appreturnonlybasicglsltype", "" }, - { "nv!ogl_app_softimage", "" }, - { "nv!ogl_app_supportbits2", "" }, - { "nv!ogl_assumetextureismipmappedatcreation", "" }, - { "nv!ogl_b1fb0f01", "" }, - { "nv!ogl_b3edd5", "" }, - { "nv!ogl_b40d9e03d", "" }, - { "nv!ogl_b7f6275666", "" }, - { "nv!ogl_b812c1", "" }, - { "nv!ogl_ba14ba1a", "" }, - { "nv!ogl_ba14ba1b", "" }, - { "nv!ogl_bd7559", "" }, - { "nv!ogl_bd755a", "" }, - { "nv!ogl_bd755c", "" }, - { "nv!ogl_bd755d", "" }, - { "nv!ogl_be58bb", "" }, - { "nv!ogl_be92cb", "" }, - { "nv!ogl_beefcba3", "" }, - { "nv!ogl_beefcba4", "" }, - { "nv!ogl_c023777f", "" }, - { "nv!ogl_c09dc8", "" }, - { "nv!ogl_c0d340", "" }, - { "nv!ogl_c2ff374c", "" }, - { "nv!ogl_c5e9d7a3", "" }, - { "nv!ogl_c5e9d7a4", "" }, - { "nv!ogl_c5e9d7b4", "" }, - { "nv!ogl_c618f9", "" }, - { "nv!ogl_ca345840", "" }, - { "nv!ogl_cachedisable", "" }, - { "nv!ogl_channelpriorityoverride", "" }, - { "nv!ogl_cleardatastorevidmem", "" }, - { "nv!ogl_cmdbufmemoryspaceenables", "" }, - { "nv!ogl_cmdbufminwords", "" }, - { "nv!ogl_cmdbufsizewords", "" }, - { "nv!ogl_conformantblitframebufferscissor", "" }, - { "nv!ogl_conformantincompletetextures", "" }, - { "nv!ogl_copybuffermethod", "" }, - { "nv!ogl_cubemapaniso", "" }, - { "nv!ogl_cubemapfiltering", "" }, - { "nv!ogl_d0e9a4d7", "" }, - { "nv!ogl_d13733f12", "" }, - { "nv!ogl_d1b399", "" }, - { "nv!ogl_d2983c32", "" }, - { "nv!ogl_d2983c33", "" }, - { "nv!ogl_d2e71b", "" }, - { "nv!ogl_d377dc", "" }, - { "nv!ogl_d377dd", "" }, - { "nv!ogl_d489f4", "" }, - { "nv!ogl_d4bce1", "" }, - { "nv!ogl_d518cb", "" }, - { "nv!ogl_d518cd", "" }, - { "nv!ogl_d518ce", "" }, - { "nv!ogl_d518d0", "" }, - { "nv!ogl_d518d1", "" }, - { "nv!ogl_d518d2", "" }, - { "nv!ogl_d518d3", "" }, - { "nv!ogl_d518d4", "" }, - { "nv!ogl_d518d5", "" }, - { "nv!ogl_d59eda", "" }, - { "nv!ogl_d83cbd", "" }, - { "nv!ogl_d8e777", "" }, - { "nv!ogl_debug_level", "" }, - { "nv!ogl_debug_mask", "" }, - { "nv!ogl_debug_options", "" }, - { "nv!ogl_devshmpageableallocations", "" }, - { "nv!ogl_df1f9812", "" }, - { "nv!ogl_df783c", "" }, - { "nv!ogl_diagenable", "" }, - { "nv!ogl_disallowcemask", "" }, - { "nv!ogl_disallowz16", "" }, - { "nv!ogl_dlmemoryspaceenables", "" }, - { "nv!ogl_e0bfec", "" }, - { "nv!ogl_e433456d", "" }, - { "nv!ogl_e435563f", "" }, - { "nv!ogl_e4cd9c", "" }, - { "nv!ogl_e5c972", "" }, - { "nv!ogl_e639ef", "" }, - { "nv!ogl_e802af", "" }, - { "nv!ogl_eae964", "" }, - { "nv!ogl_earlytexturehwallocation", "" }, - { "nv!ogl_eb92a3", "" }, - { "nv!ogl_ebca56", "" }, - { "nv!ogl_expert_detail_level", "" }, - { "nv!ogl_expert_output_mask", "" }, - { "nv!ogl_expert_report_mask", "" }, - { "nv!ogl_extensionstringnvarch", "" }, - { "nv!ogl_extensionstringversion", "" }, - { "nv!ogl_f00f1938", "" }, - { "nv!ogl_f10736", "" }, - { "nv!ogl_f1846870", "" }, - { "nv!ogl_f33bc370", "" }, - { "nv!ogl_f392a874", "" }, - { "nv!ogl_f49ae8", "" }, - { "nv!ogl_fa345cce", "" }, - { "nv!ogl_fa35cc4", "" }, - { "nv!ogl_faa14a", "" }, - { "nv!ogl_faf8a723", "" }, - { "nv!ogl_fastgs", "" }, - { "nv!ogl_fbf4ac45", "" }, - { "nv!ogl_fbo_blit_ignore_srgb", "" }, - { "nv!ogl_fc64c7", "" }, - { "nv!ogl_ff54ec97", "" }, - { "nv!ogl_ff54ec98", "" }, - { "nv!ogl_forceexitprocessdetach", "" }, - { "nv!ogl_forcerequestedesversion", "" }, - { "nv!ogl_glsynctovblank", "" }, - { "nv!ogl_gvitimeoutcontrol", "" }, - { "nv!ogl_hcctrl", "" }, - { "nv!ogl_hwstate_per_ctx", "" }, - { "nv!ogl_machinecachelimit", "" }, - { "nv!ogl_maxframesallowed", "" }, - { "nv!ogl_memmgrcachedalloclimit", "" }, - { "nv!ogl_memmgrcachedalloclimitratio", "" }, - { "nv!ogl_memmgrsysheapalloclimit", "" }, - { "nv!ogl_memmgrsysheapalloclimitratio", "" }, - { "nv!ogl_memmgrvidheapalloclimit", "" }, - { "nv!ogl_mosaic_clip_to_subdev", "" }, - { "nv!ogl_mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!ogl_mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!ogl_overlaymergeblittimerms", "" }, - { "nv!ogl_perfmon_mode", "" }, - { "nv!ogl_pixbar_mode", "" }, - { "nv!ogl_qualityenhancements", "" }, - { "nv!ogl_r27s18q28", "" }, - { "nv!ogl_r2d7c1d8", "" }, - { "nv!ogl_renderer", "" }, - { "nv!ogl_renderqualityflags", "" }, - { "nv!ogl_s3tcquality", "" }, - { "nv!ogl_shaderatomics", "" }, - { "nv!ogl_shadercacheinitsize", "" }, - { "nv!ogl_shader_disk_cache_path", "" }, - { "nv!ogl_shader_disk_cache_read_only", "" }, - { "nv!ogl_shaderobjects", "" }, - { "nv!ogl_shaderportabilitywarnings", "" }, - { "nv!ogl_shaderwarningsaserrors", "" }, - { "nv!ogl_skiptexturehostcopies", "" }, - { "nv!ogl_sli_dli_control", "" }, - { "nv!ogl_sparsetexture", "" }, - { "nv!ogl_spinlooptimeout", "" }, - { "nv!ogl_sync_to_vblank", "" }, - { "nv!ogl_sysheapreuseratio", "" }, - { "nv!ogl_sysmemtexturepromotion", "" }, - { "nv!ogl_targetflushcount", "" }, - { "nv!ogl_tearingfreeswappresent", "" }, - { "nv!ogl_texclampbehavior", "" }, - { "nv!ogl_texlodbias", "" }, - { "nv!ogl_texmemoryspaceenables", "" }, - { "nv!ogl_textureprecache", "" }, - { "nv!ogl_threadcontrol", "" }, - { "nv!ogl_threadcontrol2", "" }, - { "nv!ogl_usegvievents", "" }, - { "nv!ogl_vbomemoryspaceenables", "" }, - { "nv!ogl_vertexlimit", "" }, - { "nv!ogl_vidheapreuseratio", "" }, - { "nv!ogl_vpipe", "" }, - { "nv!ogl_vpipeformatbloatlimit", "" }, - { "nv!ogl_wglmessageboxonabort", "" }, - { "nv!ogl_writeinfolog", "" }, - { "nv!ogl_writeprogramobjectassembly", "" }, - { "nv!ogl_writeprogramobjectsource", "" }, - { "nv!ogl_xnvadapterpresent", "" }, - { "nv!ogl_yield", "" }, - { "nv!ogl_yieldfunction", "" }, - { "nv!ogl_yieldfunctionfast", "" }, - { "nv!ogl_yieldfunctionslow", "" }, - { "nv!ogl_yieldfunctionwaitfordcqueue", "" }, - { "nv!ogl_yieldfunctionwaitforframe", "" }, - { "nv!ogl_yieldfunctionwaitforgpu", "" }, - { "nv!ogl_zbctableaddhysteresis", "" }, - { "nv!overlaymergeblittimerms", "" }, - { "nv!perfmon_mode", "" }, - { "nv!persist.sys.display.resolution", "" }, - { "nv!persist.tegra.composite.fallb", "" }, - { "nv!persist.tegra.composite.policy", "" }, - { "nv!persist.tegra.composite.range", "" }, - { "nv!persist.tegra.compositor", "" }, - { "nv!persist.tegra.compositor.virt", "" }, - { "nv!persist.tegra.compression", "" }, - { "nv!persist.tegra.cursor.enable", "" }, - { "nv!persist.tegra.didim.enable", "" }, - { "nv!persist.tegra.didim.normal", "" }, - { "nv!persist.tegra.didim.video", "" }, - { "nv!persist.tegra.disp.heads", "" }, - { "nv!persist.tegra.gamma_correction", "" }, - { "nv!persist.tegra.gpu_mapping_cache", "" }, - { "nv!persist.tegra.grlayout", "" }, - { "nv!persist.tegra.hdmi.2020.10", "" }, - { "nv!persist.tegra.hdmi.2020.fake", "" }, - { "nv!persist.tegra.hdmi.2020.force", "" }, - { "nv!persist.tegra.hdmi.autorotate", "" }, - { "nv!persist.tegra.hdmi.hdr.fake", "" }, - { "nv!persist.tegra.hdmi.ignore_ratio", "" }, - { "nv!persist.tegra.hdmi.limit.clock", "" }, - { "nv!persist.tegra.hdmi.only_16_9", "" }, - { "nv!persist.tegra.hdmi.range", "" }, - { "nv!persist.tegra.hdmi.resolution", "" }, - { "nv!persist.tegra.hdmi.underscan", "" }, - { "nv!persist.tegra.hdmi.yuv.422", "" }, - { "nv!persist.tegra.hdmi.yuv.444", "" }, - { "nv!persist.tegra.hdmi.yuv.enable", "" }, - { "nv!persist.tegra.hdmi.yuv.force", "" }, - { "nv!persist.tegra.hwc.nvdc", "" }, - { "nv!persist.tegra.idle.minimum_fps", "" }, - { "nv!persist.tegra.panel.rotation", "" }, - { "nv!persist.tegra.scan_props", "" }, - { "nv!persist.tegra.stb.mode", "" }, - { "nv!persist.tegra.zbc_override", "" }, - { "nv!pixbar_mode", "" }, - { "nv!qualityenhancements", "" }, - { "nv!r27s18q28", "" }, - { "nv!r2d7c1d8", "" }, - { "nv!renderer", "" }, - { "nv!renderqualityflags", "" }, - { "nv!rmos_debug_mask", "" }, - { "nv!rmos_set_production_mode", "" }, - { "nv!s3tcquality", "" }, - { "nv!shaderatomics", "" }, - { "nv!shadercacheinitsize", "" }, - { "nv!shader_disk_cache_path", "" }, - { "nv!shader_disk_cache_read_only", "" }, - { "nv!shaderobjects", "" }, - { "nv!shaderportabilitywarnings", "" }, - { "nv!shaderwarningsaserrors", "" }, - { "nv!skiptexturehostcopies", "" }, - { "nv!sli_dli_control", "" }, - { "nv!sparsetexture", "" }, - { "nv!spinlooptimeout", "" }, - { "nv!sync_to_vblank", "" }, - { "nv!sysheapreuseratio", "" }, - { "nv!sysmemtexturepromotion", "" }, - { "nv!targetflushcount", "" }, - { "nv!tearingfreeswappresent", "" }, - { "nv!tegra.refresh", "" }, - { "nv!texclampbehavior", "" }, - { "nv!texlodbias", "" }, - { "nv!texmemoryspaceenables", "" }, - { "nv!textureprecache", "" }, - { "nv!threadcontrol", "" }, - { "nv!threadcontrol2", "" }, - { "nv!tvmr.avp.logs", "" }, - { "nv!tvmr.buffer.logs", "" }, - { "nv!tvmr.dec.prof", "" }, - { "nv!tvmr.deint.logs", "" }, - { "nv!tvmr.dfs.logs", "" }, - { "nv!tvmr.ffprof.logs", "" }, - { "nv!tvmr.game.stream", "" }, - { "nv!tvmr.general.logs", "" }, - { "nv!tvmr.input.dump", "" }, - { "nv!tvmr.seeking.logs", "" }, - { "nv!tvmr.ts_pulldown", "" }, - { "nv!usegvievents", "" }, - { "nv!vbomemoryspaceenables", "" }, - { "nv!vcc_debug_ip", "" }, - { "nv!vcc_verbose_level", "" }, - { "nv!vertexlimit", "" }, - { "nv!viccomposer.filter", "" }, - { "nv!videostats-enable", "" }, - { "nv!vidheapreuseratio", "" }, - { "nv!vpipe", "" }, - { "nv!vpipeformatbloatlimit", "" }, - { "nv!wglmessageboxonabort", "" }, - { "nv!writeinfolog", "" }, - { "nv!writeprogramobjectassembly", "" }, - { "nv!writeprogramobjectsource", "" }, - { "nv!xnvadapterpresent", "" }, - { "nv!yield", "" }, - { "nv!yieldfunction", "" }, - { "nv!yieldfunctionfast", "" }, - { "nv!yieldfunctionslow", "" }, - { "nv!yieldfunctionwaitfordcqueue", "" }, - { "nv!yieldfunctionwaitforframe", "" }, - { "nv!yieldfunctionwaitforgpu", "" }, - { "nv!zbctableaddhysteresis", "" }, - { "pcm!enable", true }, - { "pctl!intermittent_task_interval_seconds", 21600 }, - { "prepo!devmenu_prepo_page_view", false }, - { "prepo!background_processing", true }, - { "prepo!transmission_interval_min", 10 }, - { "prepo!transmission_retry_interval", 3600 }, - { "psm!evaluation_log_enabled", false }, - { "snap_shot_dump!auto_dump", false }, - { "snap_shot_dump!output_dir", "%USERPROFILE%/Documents/Nintendo/NXDMP" }, - { "snap_shot_dump!full_dump", false }, - { "systemconfig!field_testing", false }, - { "systemconfig!exhivision", false }, - { "systempowerstate!always_reboot", false }, - { "systempowerstate!power_state_message_emulation_trigger_time", 0 }, - { "systempowerstate!power_state_message_to_emulate", 0 }, - { "target_manager!device_name", "" }, - { "vulnerability!needs_update_vulnerability_policy", 0 }, - { "apm!performance_mode_policy", "auto" }, - { "apm!sdev_throttling_enabled", true }, - { "apm!sdev_throttling_additional_delay_us", 16000 }, - { "apm!battery_draining_enabled", false }, - { "apm!sdev_cpu_overclock_enabled", false }, - { "bcat!production_mode", true }, - { "bpc!enable_quasi_off", true }, - { "bsp0!usb", "UDS" }, - { "bsp0!tm_transport", "USB" }, - { "bluetooth_debug!skip_boot", false }, - { "contents_delivery!enable_debug_api", false }, - { "eupld!upload_enabled", true }, - { "fatal!transition_to_fatal", true }, - { "fatal!show_extra_info", false }, - { "gpu_core_dump!auto_dump", false }, - { "hid_debug!enables_debugpad", false }, - { "hid_debug!manages_devices", true }, - { "hid_debug!emulate_future_device", false }, - { "hid_debug!emulate_firmware_update_failure", false }, - { "hid_debug!emulate_mcu_hardware_error", false }, - { "hid_debug!firmware_update_failure_emulation_mode", 0 }, - { "jit_debug!enable_jit_debug", false }, - { "npns!background_processing", true }, - { "npns!logmanager_redirection", true }, - { "npns!sleep_processing_timeout", 30 }, - { "npns!sleep_periodic_interval", 10800 }, - { "npns!sleep_max_try_count", 5 }, - { "npns!test_mode", false }, - { "ns.applet!overlay_applet_id", "0x010000000000100c" }, - { "ns.applet!system_applet_id", "0x0100000000001000" }, - { "ns.applet!shop_applet_id", "0x010000000000100b" }, - { "ns.autoboot!enabled", true }, - { "ns.pseudodeviceid!reset_pseudo_device_id", false }, - { "nsd!environment_identifier", "lp1" }, - { "nsd!test_mode", false }, - { "ntc!is_autonomic_correction_enabled", true }, - { "ntc!autonomic_correction_interval_seconds", 432000 }, - { "ntc!autonomic_correction_failed_retry_interval_seconds", 1800 }, - { "ntc!autonomic_correction_immediate_try_count_max", 4 }, - { "ntc!autonomic_correction_immediate_try_interval_milliseconds", 5000 }, - { "nv!nv_graphics_firmware_memory_margin", false }, - { "omm!operation_mode_policy", "auto" }, - { "omm!sleep_fade_in_ms", 50 }, - { "omm!sleep_fade_out_ms", 100 }, - { "omm!charging_sign_ms", 3000 }, - { "omm!low_battery_sign_ms", 3000 }, - { "omm!sign_fade_in_ms", 0 }, - { "omm!sign_fade_out_ms", 400 }, - { "omm!sign_wait_layer_visible_ms", 100 }, - { "omm!startup_fade_in_ms", 200 }, - { "omm!startup_fade_out_ms", 400 }, - { "omm!backlight_off_ms_on_handheld_switch", 150 }, - { "omm!sleep_on_ac_ok_boot", true }, - { "pdm!save_playlog", true }, - { "productinfo!product_name", "Nintendo Switch" }, - { "productinfo!cec_osd_name", "NintendoSwitch" }, - { "ro!ease_nro_restriction", false }, - { "settings_debug!is_debug_mode_enabled", false }, - { "systemreport!enabled", true }, - { "systemsleep!enter_sleep", true }, - { "systemsleep!enter_sc7", true }, - { "systemsleep!keep_vdd_core", true }, - { "systemsleep!disable_tma_sleep", false }, - { "systemsleep!disable_auto_sleep", false }, - { "systemsleep!override_auto_sleep_time", 0 }, - { "systemsleep!sleep_pending_time_ms", 15000 }, - { "systemsleep!hush_time_after_brief_power_button_press_ms", 1000 }, - { "systemsleep!transition_timeout_sec", 60 }, - { "systemsleep!dummy_event_auto_wake", false }, - { "systemupdate!debug_id", "0x0000000000000000" }, - { "systemupdate!debug_version", 0 }, - { "systemupdate!bgnup_retry_seconds", 60 }, - { "systemupdate!enable_background_download_stress_testing", false }, - { "systemupdate!debug_id_for_content_delivery", "0x0000000000000000" }, - { "systemupdate!debug_version_for_content_delivery", 0 }, - { "systemupdate!assumed_system_applet_version", 0 }, - { "tc!iir_filter_gain_soc", 100 }, - { "tc!iir_filter_gain_pcb", 100 }, - { "tc!tskin_soc_coefficients_handheld", "[5464, 174190]" }, - { "tc!tskin_soc_coefficients_console", "[6182, 112480]" }, - { "tc!tskin_pcb_coefficients_handheld", "[5464, 174190]" }, - { "tc!tskin_pcb_coefficients_console", "[6182, 112480]" }, - { "tc!tskin_select", "both" }, - { "tc!tskin_rate_table_handheld", "[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 48000, 51, 102], [48000, 53000, 102, 153], [53000, 1000000, 153, 153], [48000, 1000000, 153, 153]]" }, - { "tc!tskin_rate_table_console", "[[-1000000, 43000, 51, 51], [43000, 53000, 51, 153], [53000, 58000, 153, 255], [58000, 1000000, 255, 255]]" }, - { "tc!rate_select", "both" }, - { "tc!log_enabled", false }, - { "tc!sleep_enabled", true }, - { "time!standard_steady_clock_test_offset_minutes", 0 }, - { "time!standard_steady_clock_rtc_update_interval_minutes", 5 }, - { "time!standard_network_clock_sufficient_accuracy_minutes", 43200 }, - { "usb!usb30_force_enabled", false }, - { "wlan_debug!skip_wlan_boot", false } - }; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Set/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Set/ResultCode.cs deleted file mode 100644 index 60d3e690..00000000 --- a/Ryujinx.HLE/HOS/Services/Set/ResultCode.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Set -{ - enum ResultCode - { - ModuleId = 105, - ErrorCodeShift = 9, - - Success = 0, - - LanguageOutOfRange = (625 << ErrorCodeShift) | ModuleId - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/IFactorySettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/IFactorySettingsServer.cs new file mode 100644 index 00000000..4dd344f8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/IFactorySettingsServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am.Tcap +{ + [Service("set:cal")] + class IFactorySettingsServer : IpcService + { + public IFactorySettingsServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/IFirmwareDebugSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/IFirmwareDebugSettingsServer.cs new file mode 100644 index 00000000..3b7e1af2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/IFirmwareDebugSettingsServer.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Settings +{ + [Service("set:fd")] + class IFirmwareDebugSettingsServer : IpcService + { + public IFirmwareDebugSettingsServer(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/ISettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/ISettingsServer.cs new file mode 100644 index 00000000..2d2512df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/ISettingsServer.cs @@ -0,0 +1,109 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.SystemState; +using System; + +namespace Ryujinx.HLE.HOS.Services.Settings +{ + [Service("set")] + class ISettingsServer : IpcService + { + public ISettingsServer(ServiceCtx context) { } + + [Command(0)] + // GetLanguageCode() -> nn::settings::LanguageCode + public ResultCode GetLanguageCode(ServiceCtx context) + { + context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode); + + return ResultCode.Success; + } + + [Command(1)] + // GetAvailableLanguageCodes() -> (u32, buffer) + public ResultCode GetAvailableLanguageCodes(ServiceCtx context) + { + return GetAvailableLanguagesCodesImpl( + context, + context.Request.RecvListBuff[0].Position, + context.Request.RecvListBuff[0].Size, + 0xF); + } + + [Command(2)] // 4.0.0+ + // MakeLanguageCode(nn::settings::Language language_index) -> nn::settings::LanguageCode + public ResultCode MakeLanguageCode(ServiceCtx context) + { + int languageIndex = context.RequestData.ReadInt32(); + + if ((uint)languageIndex >= (uint)SystemStateMgr.LanguageCodes.Length) + { + return ResultCode.LanguageOutOfRange; + } + + context.ResponseData.Write(SystemStateMgr.GetLanguageCode(languageIndex)); + + return ResultCode.Success; + } + + [Command(3)] + // GetAvailableLanguageCodeCount() -> u32 + public ResultCode GetAvailableLanguageCodeCount(ServiceCtx context) + { + context.ResponseData.Write(Math.Min(SystemStateMgr.LanguageCodes.Length, 0xF)); + + return ResultCode.Success; + } + + [Command(5)] + // GetAvailableLanguageCodes2() -> (u32, buffer) + public ResultCode GetAvailableLanguageCodes2(ServiceCtx context) + { + return GetAvailableLanguagesCodesImpl( + context, + context.Request.ReceiveBuff[0].Position, + context.Request.ReceiveBuff[0].Size, + SystemStateMgr.LanguageCodes.Length); + } + + [Command(6)] + // GetAvailableLanguageCodeCount2() -> u32 + public ResultCode GetAvailableLanguageCodeCount2(ServiceCtx context) + { + context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); + + return ResultCode.Success; + } + + [Command(8)] // 5.0.0+ + // GetQuestFlag() -> bool + public ResultCode GetQuestFlag(ServiceCtx context) + { + context.ResponseData.Write(false); + + Logger.PrintStub(LogClass.ServiceSet); + + return ResultCode.Success; + } + + public ResultCode GetAvailableLanguagesCodesImpl(ServiceCtx context, long position, long size, int maxSize) + { + int count = (int)(size / 8); + + if (count > maxSize) + { + count = maxSize; + } + + for (int index = 0; index < count; index++) + { + context.Memory.WriteInt64(position, SystemStateMgr.GetLanguageCode(index)); + + position += 8; + } + + context.ResponseData.Write(count); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs new file mode 100644 index 00000000..7af78dbf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs @@ -0,0 +1,198 @@ +using LibHac.Fs; +using LibHac.Fs.NcaUtils; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.HOS.SystemState; +using System; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Settings +{ + [Service("set:sys")] + class ISystemSettingsServer : IpcService + { + public ISystemSettingsServer(ServiceCtx context) { } + + [Command(3)] + // GetFirmwareVersion() -> buffer + public ResultCode GetFirmwareVersion(ServiceCtx context) + { + return GetFirmwareVersion2(context); + } + + [Command(4)] + // GetFirmwareVersion2() -> buffer + public ResultCode GetFirmwareVersion2(ServiceCtx context) + { + long replyPos = context.Request.RecvListBuff[0].Position; + long replySize = context.Request.RecvListBuff[0].Size; + + byte[] firmwareData = GetFirmwareData(context.Device); + + if (firmwareData != null) + { + context.Memory.WriteBytes(replyPos, firmwareData); + + return ResultCode.Success; + } + + const byte majorFwVersion = 0x03; + const byte minorFwVersion = 0x00; + const byte microFwVersion = 0x00; + const byte unknown = 0x00; //Build? + + const int revisionNumber = 0x0A; + + const string platform = "NX"; + const string unknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47"; + const string version = "3.0.0"; + const string build = "NintendoSDK Firmware for NX 3.0.0-10.0"; + + // http://switchbrew.org/index.php?title=System_Version_Title + using (MemoryStream ms = new MemoryStream(0x100)) + { + BinaryWriter writer = new BinaryWriter(ms); + + writer.Write(majorFwVersion); + writer.Write(minorFwVersion); + writer.Write(microFwVersion); + writer.Write(unknown); + + writer.Write(revisionNumber); + + writer.Write(Encoding.ASCII.GetBytes(platform)); + + ms.Seek(0x28, SeekOrigin.Begin); + + writer.Write(Encoding.ASCII.GetBytes(unknownHex)); + + ms.Seek(0x68, SeekOrigin.Begin); + + writer.Write(Encoding.ASCII.GetBytes(version)); + + ms.Seek(0x80, SeekOrigin.Begin); + + writer.Write(Encoding.ASCII.GetBytes(build)); + + context.Memory.WriteBytes(replyPos, ms.ToArray()); + } + + return ResultCode.Success; + } + + [Command(23)] + // GetColorSetId() -> i32 + public ResultCode GetColorSetId(ServiceCtx context) + { + context.ResponseData.Write((int)context.Device.System.State.ThemeColor); + + return ResultCode.Success; + } + + [Command(24)] + // GetColorSetId() -> i32 + public ResultCode SetColorSetId(ServiceCtx context) + { + int colorSetId = context.RequestData.ReadInt32(); + + context.Device.System.State.ThemeColor = (ColorSet)colorSetId; + + return ResultCode.Success; + } + + [Command(38)] + // GetSettingsItemValue(buffer, buffer) -> (u64, buffer) + public ResultCode GetSettingsItemValue(ServiceCtx context) + { + long classPos = context.Request.PtrBuff[0].Position; + long classSize = context.Request.PtrBuff[0].Size; + + long namePos = context.Request.PtrBuff[1].Position; + long nameSize = context.Request.PtrBuff[1].Size; + + long replyPos = context.Request.ReceiveBuff[0].Position; + long replySize = context.Request.ReceiveBuff[0].Size; + + byte[] Class = context.Memory.ReadBytes(classPos, classSize); + byte[] name = context.Memory.ReadBytes(namePos, nameSize); + + string askedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(name).Trim('\0'); + + NxSettings.Settings.TryGetValue(askedSetting, out object nxSetting); + + if (nxSetting != null) + { + byte[] settingBuffer = new byte[replySize]; + + if (nxSetting is string stringValue) + { + if (stringValue.Length + 1 > replySize) + { + Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} String value size is too big!"); + } + else + { + settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0"); + } + } + + if (nxSetting is int intValue) + { + settingBuffer = BitConverter.GetBytes(intValue); + } + else if (nxSetting is bool boolValue) + { + settingBuffer[0] = boolValue ? (byte)1 : (byte)0; + } + else + { + throw new NotImplementedException(nxSetting.GetType().Name); + } + + context.Memory.WriteBytes(replyPos, settingBuffer); + + Logger.PrintDebug(LogClass.ServiceSet, $"{askedSetting} set value: {nxSetting} as {nxSetting.GetType()}"); + } + else + { + Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} not found!"); + } + + return ResultCode.Success; + } + + public byte[] GetFirmwareData(Switch device) + { + long titleId = 0x0100000000000809; + string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, ContentType.Data); + + if (string.IsNullOrWhiteSpace(contentPath)) + { + return null; + } + + string firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath); + + using(IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read)) + { + Nca firmwareContent = new Nca(device.System.KeySet, firmwareStorage); + + if (!firmwareContent.CanOpenSection(NcaSectionType.Data)) + { + return null; + } + + IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel); + + IFile firmwareFile = firmwareRomFs.OpenFile("/file", OpenMode.Read); + + byte[] data = new byte[firmwareFile.GetSize()]; + + firmwareFile.Read(data, 0); + + return data; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/NxSettings.cs b/Ryujinx.HLE/HOS/Services/Settings/NxSettings.cs new file mode 100644 index 00000000..b679005e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/NxSettings.cs @@ -0,0 +1,1711 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Settings +{ + static class NxSettings + { + // Generated automatically from a Switch 3.0 config file (Tid: 0100000000000818). + public static Dictionary Settings = new Dictionary + { + { "account!na_required_for_network_service", true }, + { "account.daemon!background_awaking_periodicity", 10800 }, + { "account.daemon!schedule_periodicity", 3600 }, + { "account.daemon!profile_sync_interval", 18000 }, + { "account.daemon!na_info_refresh_interval", 46800 }, + { "am.display!transition_layer_enabled", true }, + { "am.gpu!gpu_scheduling_enabled", true }, + { "am.gpu!gpu_scheduling_frame_time_us", 116666 }, + { "am.gpu!gpu_scheduling_fg_app_us", 116166 }, + { "am.gpu!gpu_scheduling_bg_app_us", 104500 }, + { "am.gpu!gpu_scheduling_oa_us", 500 }, + { "am.gpu!gpu_scheduling_fg_sa_us", 11666 }, + { "am.gpu!gpu_scheduling_bg_sa_us", 0 }, + { "am.gpu!gpu_scheduling_fg_la_us", 11666 }, + { "am.gpu!gpu_scheduling_partial_fg_la_us", 2000 }, + { "am.gpu!gpu_scheduling_bg_la_us", 0 }, + { "audio!audren_log_enabled", false }, + { "audio!audout_log_enabled", false }, + { "audio!audin_log_enabled", false }, + { "audio!hwopus_log_enabled", false }, + { "audio!adsp_log_enabled", false }, + { "audio!suspend_for_debugger_enabled", false }, + { "audio!uac_speaker_enabled", false }, + { "bgtc!enable_halfawake", 1 }, + { "bgtc!enable_battery_saver", 1 }, + { "bgtc!leaving_halfawake_margin", 3 }, + { "bgtc!battery_threshold_save", 20 }, + { "bgtc!battery_threshold_stop", 20 }, + { "bgtc!minimum_interval_normal", 1800 }, + { "bgtc!minimum_interval_save", 86400 }, + { "boot!force_maintenance", false }, + { "capsrv!screenshot_layerstack", "screenshot" }, + { "capsrv!enable_album_screenshot_filedata_verification", true }, + { "devmenu!enable_application_update", true }, + { "devmenu!enable_exhibition_mode", false }, + { "eclct!analytics_override", false }, + { "eclct!analytics_pollperiod", 86400 }, + { "err!applet_auto_close", false }, + { "friends!background_processing", true }, + { "htc!disconnection_emulation", false }, + { "idle!dim_level_percent_lcd", 10 }, + { "idle!dim_level_percent_tv", 70 }, + { "lbl!force_disable_als", false }, + { "lm!enable_sd_card_logging", false }, + { "lm!sd_card_log_output_directory", "NxBinLogs" }, + { "mii!is_db_test_mode_enabled", false }, + { "news!system_version", 2 }, + { "nfp!not_locked_tag", true }, + { "nfp!play_report", false }, + { "nifm!is_communication_control_enabled_for_test", false }, + { "nifm!connection_test_timeout", 45000 }, + { "nifm!apply_config_timeout", 30000 }, + { "nifm!ethernet_adapter_standby_time", 10000 }, + { "nim.install!prefer_delta_evenif_inefficient", false }, + { "nim.install!apply_delta_stress_storage", 0 }, + { "ns.notification!retry_interval", 60 }, + { "ns.notification!enable_network_update", true }, + { "ns.notification!enable_download_task_list", true }, + { "ns.notification!enable_version_list", true }, + { "ns.notification!enable_random_wait", true }, + { "ns.notification!debug_waiting_limit", 0 }, + { "ns.notification!enable_request_on_cold_boot", true }, + { "ns.sdcard!mount_sdcard", true }, + { "ns.sdcard!compare_sdcard", 0 }, + { "ns.gamecard!mount_gamecard_result_value", 0 }, + { "ns.gamecard!try_gamecard_access_result_value", 0 }, + { "nv!00008600", "" }, + { "nv!0007b25e", "" }, + { "nv!0083e1", "" }, + { "nv!01621887", "" }, + { "nv!03134743", "" }, + { "nv!0356afd0", "" }, + { "nv!0356afd1", "" }, + { "nv!0356afd2", "" }, + { "nv!0356afd3", "" }, + { "nv!094313", "" }, + { "nv!0x04dc09", "" }, + { "nv!0x111133", "" }, + { "nv!0x1aa483", "" }, + { "nv!0x1cb1cf", "" }, + { "nv!0x1cb1d0", "" }, + { "nv!0x1e3221", "" }, + { "nv!0x300fc8", "" }, + { "nv!0x301fc8", "" }, + { "nv!0x302fc8", "" }, + { "nv!0x3eec59", "" }, + { "nv!0x46b3ed", "" }, + { "nv!0x523dc0", "" }, + { "nv!0x523dc1", "" }, + { "nv!0x523dc2", "" }, + { "nv!0x523dc3", "" }, + { "nv!0x523dc4", "" }, + { "nv!0x523dc5", "" }, + { "nv!0x523dc6", "" }, + { "nv!0x523dd0", "" }, + { "nv!0x523dd1", "" }, + { "nv!0x523dd3", "" }, + { "nv!0x5344bb", "" }, + { "nv!0x555237", "" }, + { "nv!0x58a234", "" }, + { "nv!0x7b4428", "" }, + { "nv!0x923dc0", "" }, + { "nv!0x923dc1", "" }, + { "nv!0x923dc2", "" }, + { "nv!0x923dc3", "" }, + { "nv!0x923dc4", "" }, + { "nv!0x923dd3", "" }, + { "nv!0x9abdc5", "" }, + { "nv!0x9abdc6", "" }, + { "nv!0xaaa36c", "" }, + { "nv!0xb09da0", "" }, + { "nv!0xb09da1", "" }, + { "nv!0xb09da2", "" }, + { "nv!0xb09da3", "" }, + { "nv!0xb09da4", "" }, + { "nv!0xb09da5", "" }, + { "nv!0xb0b348", "" }, + { "nv!0xb0b349", "" }, + { "nv!0xbb558f", "" }, + { "nv!0xbd10fb", "" }, + { "nv!0xc32ad3", "" }, + { "nv!0xce2348", "" }, + { "nv!0xcfd81f", "" }, + { "nv!0xe0036b", "" }, + { "nv!0xe01f2d", "" }, + { "nv!0xe17212", "" }, + { "nv!0xeae966", "" }, + { "nv!0xed4f82", "" }, + { "nv!0xf12335", "" }, + { "nv!0xf12336", "" }, + { "nv!10261989", "" }, + { "nv!1042d483", "" }, + { "nv!10572898", "" }, + { "nv!115631", "" }, + { "nv!12950094", "" }, + { "nv!1314f311", "" }, + { "nv!1314f312", "" }, + { "nv!13279512", "" }, + { "nv!13813496", "" }, + { "nv!14507179", "" }, + { "nv!15694569", "" }, + { "nv!16936964", "" }, + { "nv!17aa230c", "" }, + { "nv!182054", "" }, + { "nv!18273275", "" }, + { "nv!18273276", "" }, + { "nv!1854d03b", "" }, + { "nv!18add00d", "" }, + { "nv!19156670", "" }, + { "nv!19286545", "" }, + { "nv!1a298e9f", "" }, + { "nv!1acf43fe", "" }, + { "nv!1bda43fe", "" }, + { "nv!1c3b92", "" }, + { "nv!21509920", "" }, + { "nv!215323457", "" }, + { "nv!2165ad", "" }, + { "nv!2165ae", "" }, + { "nv!21be9c", "" }, + { "nv!233264316", "" }, + { "nv!234557580", "" }, + { "nv!23cd0e", "" }, + { "nv!24189123", "" }, + { "nv!2443266", "" }, + { "nv!25025519", "" }, + { "nv!255e39", "" }, + { "nv!2583364", "" }, + { "nv!2888c1", "" }, + { "nv!28ca3e", "" }, + { "nv!29871243", "" }, + { "nv!2a1f64", "" }, + { "nv!2dc432", "" }, + { "nv!2de437", "" }, + { "nv!2f3bb89c", "" }, + { "nv!2fd652", "" }, + { "nv!3001ac", "" }, + { "nv!31298772", "" }, + { "nv!313233", "" }, + { "nv!31f7d603", "" }, + { "nv!320ce4", "" }, + { "nv!32153248", "" }, + { "nv!32153249", "" }, + { "nv!335bca", "" }, + { "nv!342abb", "" }, + { "nv!34dfe6", "" }, + { "nv!34dfe7", "" }, + { "nv!34dfe8", "" }, + { "nv!34dfe9", "" }, + { "nv!35201578", "" }, + { "nv!359278", "" }, + { "nv!37f53a", "" }, + { "nv!38144972", "" }, + { "nv!38542646", "" }, + { "nv!3b74c9", "" }, + { "nv!3c136f", "" }, + { "nv!3cf72823", "" }, + { "nv!3d7af029", "" }, + { "nv!3ff34782", "" }, + { "nv!4129618", "" }, + { "nv!4189fac3", "" }, + { "nv!420bd4", "" }, + { "nv!42a699", "" }, + { "nv!441369", "" }, + { "nv!4458713e", "" }, + { "nv!4554b6", "" }, + { "nv!457425", "" }, + { "nv!4603b207", "" }, + { "nv!46574957", "" }, + { "nv!46574958", "" }, + { "nv!46813529", "" }, + { "nv!46f1e13d", "" }, + { "nv!47534c43", "" }, + { "nv!48550336", "" }, + { "nv!48576893", "" }, + { "nv!48576894", "" }, + { "nv!4889ac02", "" }, + { "nv!49005740", "" }, + { "nv!49867584", "" }, + { "nv!49960973", "" }, + { "nv!4a5341", "" }, + { "nv!4f4e48", "" }, + { "nv!4f8a0a", "" }, + { "nv!50299698", "" }, + { "nv!50299699", "" }, + { "nv!50361291", "" }, + { "nv!5242ae", "" }, + { "nv!53d30c", "" }, + { "nv!56347a", "" }, + { "nv!563a95f1", "" }, + { "nv!573823", "" }, + { "nv!58027529", "" }, + { "nv!5d2d63", "" }, + { "nv!5f7e3b", "" }, + { "nv!60461793", "" }, + { "nv!60d355", "" }, + { "nv!616627aa", "" }, + { "nv!62317182", "" }, + { "nv!6253fa2e", "" }, + { "nv!64100768", "" }, + { "nv!64100769", "" }, + { "nv!64100770", "" }, + { "nv!647395", "" }, + { "nv!66543234", "" }, + { "nv!67674763", "" }, + { "nv!67739784", "" }, + { "nv!68fb9c", "" }, + { "nv!69801276", "" }, + { "nv!6af9fa2f", "" }, + { "nv!6af9fa3f", "" }, + { "nv!6af9fa4f", "" }, + { "nv!6bd8c7", "" }, + { "nv!6c7691", "" }, + { "nv!6d4296ce", "" }, + { "nv!6dd7e7", "" }, + { "nv!6dd7e8", "" }, + { "nv!6fe11ec1", "" }, + { "nv!716511763", "" }, + { "nv!72504593", "" }, + { "nv!73304097", "" }, + { "nv!73314098", "" }, + { "nv!74095213", "" }, + { "nv!74095213a", "" }, + { "nv!74095213b", "" }, + { "nv!74095214", "" }, + { "nv!748f9649", "" }, + { "nv!75494732", "" }, + { "nv!78452832", "" }, + { "nv!784561", "" }, + { "nv!78e16b9c", "" }, + { "nv!79251225", "" }, + { "nv!7c128b", "" }, + { "nv!7ccd93", "" }, + { "nv!7df8d1", "" }, + { "nv!800c2310", "" }, + { "nv!80546710", "" }, + { "nv!80772310", "" }, + { "nv!808ee280", "" }, + { "nv!81131154", "" }, + { "nv!81274457", "" }, + { "nv!8292291f", "" }, + { "nv!83498426", "" }, + { "nv!84993794", "" }, + { "nv!84995585", "" }, + { "nv!84a0a0", "" }, + { "nv!852142", "" }, + { "nv!85612309", "" }, + { "nv!85612310", "" }, + { "nv!85612311", "" }, + { "nv!85612312", "" }, + { "nv!8623ff27", "" }, + { "nv!87364952", "" }, + { "nv!87f6275666", "" }, + { "nv!886748", "" }, + { "nv!89894423", "" }, + { "nv!8ad8a75", "" }, + { "nv!8ad8ad00", "" }, + { "nv!8bb815", "" }, + { "nv!8bb817", "" }, + { "nv!8bb818", "" }, + { "nv!8bb819", "" }, + { "nv!8e640cd1", "" }, + { "nv!8f34971a", "" }, + { "nv!8f773984", "" }, + { "nv!8f7a7d", "" }, + { "nv!902486209", "" }, + { "nv!90482571", "" }, + { "nv!91214835", "" }, + { "nv!912848290", "" }, + { "nv!915e56", "" }, + { "nv!92179063", "" }, + { "nv!92179064", "" }, + { "nv!92179065", "" }, + { "nv!92179066", "" }, + { "nv!92350358", "" }, + { "nv!92809063", "" }, + { "nv!92809064", "" }, + { "nv!92809065", "" }, + { "nv!92809066", "" }, + { "nv!92920143", "" }, + { "nv!93a89b12", "" }, + { "nv!93a89c0b", "" }, + { "nv!94812574", "" }, + { "nv!95282304", "" }, + { "nv!95394027", "" }, + { "nv!959b1f", "" }, + { "nv!9638af", "" }, + { "nv!96fd59", "" }, + { "nv!97f6275666", "" }, + { "nv!97f6275667", "" }, + { "nv!97f6275668", "" }, + { "nv!97f6275669", "" }, + { "nv!97f627566a", "" }, + { "nv!97f627566b", "" }, + { "nv!97f627566d", "" }, + { "nv!97f627566e", "" }, + { "nv!97f627566f", "" }, + { "nv!97f6275670", "" }, + { "nv!97f6275671", "" }, + { "nv!97f727566e", "" }, + { "nv!98480775", "" }, + { "nv!98480776", "" }, + { "nv!98480777", "" }, + { "nv!992431", "" }, + { "nv!9aa29065", "" }, + { "nv!9af32c", "" }, + { "nv!9af32d", "" }, + { "nv!9af32e", "" }, + { "nv!9c108b71", "" }, + { "nv!9f279065", "" }, + { "nv!a01bc728", "" }, + { "nv!a13b46c80", "" }, + { "nv!a22eb0", "" }, + { "nv!a2fb451e", "" }, + { "nv!a3456abe", "" }, + { "nv!a7044887", "" }, + { "nv!a7149200", "" }, + { "nv!a766215670", "" }, + { "nv!aac_drc_boost", "" }, + { "nv!aac_drc_cut", "" }, + { "nv!aac_drc_enc_target_level", "" }, + { "nv!aac_drc_heavy", "" }, + { "nv!aac_drc_reference_level", "" }, + { "nv!aalinegamma", "" }, + { "nv!aalinetweaks", "" }, + { "nv!ab34ee01", "" }, + { "nv!ab34ee02", "" }, + { "nv!ab34ee03", "" }, + { "nv!ac0274", "" }, + { "nv!af73c63e", "" }, + { "nv!af73c63f", "" }, + { "nv!af9927", "" }, + { "nv!afoverride", "" }, + { "nv!allocdeviceevents", "" }, + { "nv!applicationkey", "" }, + { "nv!appreturnonlybasicglsltype", "" }, + { "nv!app_softimage", "" }, + { "nv!app_supportbits2", "" }, + { "nv!assumetextureismipmappedatcreation", "" }, + { "nv!b1fb0f01", "" }, + { "nv!b3edd5", "" }, + { "nv!b40d9e03d", "" }, + { "nv!b7f6275666", "" }, + { "nv!b812c1", "" }, + { "nv!ba14ba1a", "" }, + { "nv!ba14ba1b", "" }, + { "nv!bd7559", "" }, + { "nv!bd755a", "" }, + { "nv!bd755c", "" }, + { "nv!bd755d", "" }, + { "nv!be58bb", "" }, + { "nv!be92cb", "" }, + { "nv!beefcba3", "" }, + { "nv!beefcba4", "" }, + { "nv!c023777f", "" }, + { "nv!c09dc8", "" }, + { "nv!c0d340", "" }, + { "nv!c2ff374c", "" }, + { "nv!c5e9d7a3", "" }, + { "nv!c5e9d7a4", "" }, + { "nv!c5e9d7b4", "" }, + { "nv!c618f9", "" }, + { "nv!ca345840", "" }, + { "nv!cachedisable", "" }, + { "nv!cast.on", "" }, + { "nv!cde", "" }, + { "nv!channelpriorityoverride", "" }, + { "nv!cleardatastorevidmem", "" }, + { "nv!cmdbufmemoryspaceenables", "" }, + { "nv!cmdbufminwords", "" }, + { "nv!cmdbufsizewords", "" }, + { "nv!conformantblitframebufferscissor", "" }, + { "nv!conformantincompletetextures", "" }, + { "nv!copybuffermethod", "" }, + { "nv!cubemapaniso", "" }, + { "nv!cubemapfiltering", "" }, + { "nv!d0e9a4d7", "" }, + { "nv!d13733f12", "" }, + { "nv!d1b399", "" }, + { "nv!d2983c32", "" }, + { "nv!d2983c33", "" }, + { "nv!d2e71b", "" }, + { "nv!d377dc", "" }, + { "nv!d377dd", "" }, + { "nv!d489f4", "" }, + { "nv!d4bce1", "" }, + { "nv!d518cb", "" }, + { "nv!d518cd", "" }, + { "nv!d518ce", "" }, + { "nv!d518d0", "" }, + { "nv!d518d1", "" }, + { "nv!d518d2", "" }, + { "nv!d518d3", "" }, + { "nv!d518d4", "" }, + { "nv!d518d5", "" }, + { "nv!d59eda", "" }, + { "nv!d83cbd", "" }, + { "nv!d8e777", "" }, + { "nv!debug_level", "" }, + { "nv!debug_mask", "" }, + { "nv!debug_options", "" }, + { "nv!devshmpageableallocations", "" }, + { "nv!df1f9812", "" }, + { "nv!df783c", "" }, + { "nv!diagenable", "" }, + { "nv!disallowcemask", "" }, + { "nv!disallowz16", "" }, + { "nv!dlmemoryspaceenables", "" }, + { "nv!e0bfec", "" }, + { "nv!e433456d", "" }, + { "nv!e435563f", "" }, + { "nv!e4cd9c", "" }, + { "nv!e5c972", "" }, + { "nv!e639ef", "" }, + { "nv!e802af", "" }, + { "nv!eae964", "" }, + { "nv!earlytexturehwallocation", "" }, + { "nv!eb92a3", "" }, + { "nv!ebca56", "" }, + { "nv!enable-noaud", "" }, + { "nv!enable-noavs", "" }, + { "nv!enable-prof", "" }, + { "nv!enable-sxesmode", "" }, + { "nv!enable-ulld", "" }, + { "nv!expert_detail_level", "" }, + { "nv!expert_output_mask", "" }, + { "nv!expert_report_mask", "" }, + { "nv!extensionstringnvarch", "" }, + { "nv!extensionstringversion", "" }, + { "nv!f00f1938", "" }, + { "nv!f10736", "" }, + { "nv!f1846870", "" }, + { "nv!f33bc370", "" }, + { "nv!f392a874", "" }, + { "nv!f49ae8", "" }, + { "nv!fa345cce", "" }, + { "nv!fa35cc4", "" }, + { "nv!faa14a", "" }, + { "nv!faf8a723", "" }, + { "nv!fastgs", "" }, + { "nv!fbf4ac45", "" }, + { "nv!fbo_blit_ignore_srgb", "" }, + { "nv!fc64c7", "" }, + { "nv!ff54ec97", "" }, + { "nv!ff54ec98", "" }, + { "nv!forceexitprocessdetach", "" }, + { "nv!forcerequestedesversion", "" }, + { "nv!__gl_", "" }, + { "nv!__gl_00008600", "" }, + { "nv!__gl_0007b25e", "" }, + { "nv!__gl_0083e1", "" }, + { "nv!__gl_01621887", "" }, + { "nv!__gl_03134743", "" }, + { "nv!__gl_0356afd0", "" }, + { "nv!__gl_0356afd1", "" }, + { "nv!__gl_0356afd2", "" }, + { "nv!__gl_0356afd3", "" }, + { "nv!__gl_094313", "" }, + { "nv!__gl_0x04dc09", "" }, + { "nv!__gl_0x111133", "" }, + { "nv!__gl_0x1aa483", "" }, + { "nv!__gl_0x1cb1cf", "" }, + { "nv!__gl_0x1cb1d0", "" }, + { "nv!__gl_0x1e3221", "" }, + { "nv!__gl_0x300fc8", "" }, + { "nv!__gl_0x301fc8", "" }, + { "nv!__gl_0x302fc8", "" }, + { "nv!__gl_0x3eec59", "" }, + { "nv!__gl_0x46b3ed", "" }, + { "nv!__gl_0x523dc0", "" }, + { "nv!__gl_0x523dc1", "" }, + { "nv!__gl_0x523dc2", "" }, + { "nv!__gl_0x523dc3", "" }, + { "nv!__gl_0x523dc4", "" }, + { "nv!__gl_0x523dc5", "" }, + { "nv!__gl_0x523dc6", "" }, + { "nv!__gl_0x523dd0", "" }, + { "nv!__gl_0x523dd1", "" }, + { "nv!__gl_0x523dd3", "" }, + { "nv!__gl_0x5344bb", "" }, + { "nv!__gl_0x555237", "" }, + { "nv!__gl_0x58a234", "" }, + { "nv!__gl_0x7b4428", "" }, + { "nv!__gl_0x923dc0", "" }, + { "nv!__gl_0x923dc1", "" }, + { "nv!__gl_0x923dc2", "" }, + { "nv!__gl_0x923dc3", "" }, + { "nv!__gl_0x923dc4", "" }, + { "nv!__gl_0x923dd3", "" }, + { "nv!__gl_0x9abdc5", "" }, + { "nv!__gl_0x9abdc6", "" }, + { "nv!__gl_0xaaa36c", "" }, + { "nv!__gl_0xb09da0", "" }, + { "nv!__gl_0xb09da1", "" }, + { "nv!__gl_0xb09da2", "" }, + { "nv!__gl_0xb09da3", "" }, + { "nv!__gl_0xb09da4", "" }, + { "nv!__gl_0xb09da5", "" }, + { "nv!__gl_0xb0b348", "" }, + { "nv!__gl_0xb0b349", "" }, + { "nv!__gl_0xbb558f", "" }, + { "nv!__gl_0xbd10fb", "" }, + { "nv!__gl_0xc32ad3", "" }, + { "nv!__gl_0xce2348", "" }, + { "nv!__gl_0xcfd81f", "" }, + { "nv!__gl_0xe0036b", "" }, + { "nv!__gl_0xe01f2d", "" }, + { "nv!__gl_0xe17212", "" }, + { "nv!__gl_0xeae966", "" }, + { "nv!__gl_0xed4f82", "" }, + { "nv!__gl_0xf12335", "" }, + { "nv!__gl_0xf12336", "" }, + { "nv!__gl_10261989", "" }, + { "nv!__gl_1042d483", "" }, + { "nv!__gl_10572898", "" }, + { "nv!__gl_115631", "" }, + { "nv!__gl_12950094", "" }, + { "nv!__gl_1314f311", "" }, + { "nv!__gl_1314f312", "" }, + { "nv!__gl_13279512", "" }, + { "nv!__gl_13813496", "" }, + { "nv!__gl_14507179", "" }, + { "nv!__gl_15694569", "" }, + { "nv!__gl_16936964", "" }, + { "nv!__gl_17aa230c", "" }, + { "nv!__gl_182054", "" }, + { "nv!__gl_18273275", "" }, + { "nv!__gl_18273276", "" }, + { "nv!__gl_1854d03b", "" }, + { "nv!__gl_18add00d", "" }, + { "nv!__gl_19156670", "" }, + { "nv!__gl_19286545", "" }, + { "nv!__gl_1a298e9f", "" }, + { "nv!__gl_1acf43fe", "" }, + { "nv!__gl_1bda43fe", "" }, + { "nv!__gl_1c3b92", "" }, + { "nv!__gl_21509920", "" }, + { "nv!__gl_215323457", "" }, + { "nv!__gl_2165ad", "" }, + { "nv!__gl_2165ae", "" }, + { "nv!__gl_21be9c", "" }, + { "nv!__gl_233264316", "" }, + { "nv!__gl_234557580", "" }, + { "nv!__gl_23cd0e", "" }, + { "nv!__gl_24189123", "" }, + { "nv!__gl_2443266", "" }, + { "nv!__gl_25025519", "" }, + { "nv!__gl_255e39", "" }, + { "nv!__gl_2583364", "" }, + { "nv!__gl_2888c1", "" }, + { "nv!__gl_28ca3e", "" }, + { "nv!__gl_29871243", "" }, + { "nv!__gl_2a1f64", "" }, + { "nv!__gl_2dc432", "" }, + { "nv!__gl_2de437", "" }, + { "nv!__gl_2f3bb89c", "" }, + { "nv!__gl_2fd652", "" }, + { "nv!__gl_3001ac", "" }, + { "nv!__gl_31298772", "" }, + { "nv!__gl_313233", "" }, + { "nv!__gl_31f7d603", "" }, + { "nv!__gl_320ce4", "" }, + { "nv!__gl_32153248", "" }, + { "nv!__gl_32153249", "" }, + { "nv!__gl_335bca", "" }, + { "nv!__gl_342abb", "" }, + { "nv!__gl_34dfe6", "" }, + { "nv!__gl_34dfe7", "" }, + { "nv!__gl_34dfe8", "" }, + { "nv!__gl_34dfe9", "" }, + { "nv!__gl_35201578", "" }, + { "nv!__gl_359278", "" }, + { "nv!__gl_37f53a", "" }, + { "nv!__gl_38144972", "" }, + { "nv!__gl_38542646", "" }, + { "nv!__gl_3b74c9", "" }, + { "nv!__gl_3c136f", "" }, + { "nv!__gl_3cf72823", "" }, + { "nv!__gl_3d7af029", "" }, + { "nv!__gl_3ff34782", "" }, + { "nv!__gl_4129618", "" }, + { "nv!__gl_4189fac3", "" }, + { "nv!__gl_420bd4", "" }, + { "nv!__gl_42a699", "" }, + { "nv!__gl_441369", "" }, + { "nv!__gl_4458713e", "" }, + { "nv!__gl_4554b6", "" }, + { "nv!__gl_457425", "" }, + { "nv!__gl_4603b207", "" }, + { "nv!__gl_46574957", "" }, + { "nv!__gl_46574958", "" }, + { "nv!__gl_46813529", "" }, + { "nv!__gl_46f1e13d", "" }, + { "nv!__gl_47534c43", "" }, + { "nv!__gl_48550336", "" }, + { "nv!__gl_48576893", "" }, + { "nv!__gl_48576894", "" }, + { "nv!__gl_4889ac02", "" }, + { "nv!__gl_49005740", "" }, + { "nv!__gl_49867584", "" }, + { "nv!__gl_49960973", "" }, + { "nv!__gl_4a5341", "" }, + { "nv!__gl_4f4e48", "" }, + { "nv!__gl_4f8a0a", "" }, + { "nv!__gl_50299698", "" }, + { "nv!__gl_50299699", "" }, + { "nv!__gl_50361291", "" }, + { "nv!__gl_5242ae", "" }, + { "nv!__gl_53d30c", "" }, + { "nv!__gl_56347a", "" }, + { "nv!__gl_563a95f1", "" }, + { "nv!__gl_573823", "" }, + { "nv!__gl_58027529", "" }, + { "nv!__gl_5d2d63", "" }, + { "nv!__gl_5f7e3b", "" }, + { "nv!__gl_60461793", "" }, + { "nv!__gl_60d355", "" }, + { "nv!__gl_616627aa", "" }, + { "nv!__gl_62317182", "" }, + { "nv!__gl_6253fa2e", "" }, + { "nv!__gl_64100768", "" }, + { "nv!__gl_64100769", "" }, + { "nv!__gl_64100770", "" }, + { "nv!__gl_647395", "" }, + { "nv!__gl_66543234", "" }, + { "nv!__gl_67674763", "" }, + { "nv!__gl_67739784", "" }, + { "nv!__gl_68fb9c", "" }, + { "nv!__gl_69801276", "" }, + { "nv!__gl_6af9fa2f", "" }, + { "nv!__gl_6af9fa3f", "" }, + { "nv!__gl_6af9fa4f", "" }, + { "nv!__gl_6bd8c7", "" }, + { "nv!__gl_6c7691", "" }, + { "nv!__gl_6d4296ce", "" }, + { "nv!__gl_6dd7e7", "" }, + { "nv!__gl_6dd7e8", "" }, + { "nv!__gl_6fe11ec1", "" }, + { "nv!__gl_716511763", "" }, + { "nv!__gl_72504593", "" }, + { "nv!__gl_73304097", "" }, + { "nv!__gl_73314098", "" }, + { "nv!__gl_74095213", "" }, + { "nv!__gl_74095213a", "" }, + { "nv!__gl_74095213b", "" }, + { "nv!__gl_74095214", "" }, + { "nv!__gl_748f9649", "" }, + { "nv!__gl_75494732", "" }, + { "nv!__gl_78452832", "" }, + { "nv!__gl_784561", "" }, + { "nv!__gl_78e16b9c", "" }, + { "nv!__gl_79251225", "" }, + { "nv!__gl_7c128b", "" }, + { "nv!__gl_7ccd93", "" }, + { "nv!__gl_7df8d1", "" }, + { "nv!__gl_800c2310", "" }, + { "nv!__gl_80546710", "" }, + { "nv!__gl_80772310", "" }, + { "nv!__gl_808ee280", "" }, + { "nv!__gl_81131154", "" }, + { "nv!__gl_81274457", "" }, + { "nv!__gl_8292291f", "" }, + { "nv!__gl_83498426", "" }, + { "nv!__gl_84993794", "" }, + { "nv!__gl_84995585", "" }, + { "nv!__gl_84a0a0", "" }, + { "nv!__gl_852142", "" }, + { "nv!__gl_85612309", "" }, + { "nv!__gl_85612310", "" }, + { "nv!__gl_85612311", "" }, + { "nv!__gl_85612312", "" }, + { "nv!__gl_8623ff27", "" }, + { "nv!__gl_87364952", "" }, + { "nv!__gl_87f6275666", "" }, + { "nv!__gl_886748", "" }, + { "nv!__gl_89894423", "" }, + { "nv!__gl_8ad8a75", "" }, + { "nv!__gl_8ad8ad00", "" }, + { "nv!__gl_8bb815", "" }, + { "nv!__gl_8bb817", "" }, + { "nv!__gl_8bb818", "" }, + { "nv!__gl_8bb819", "" }, + { "nv!__gl_8e640cd1", "" }, + { "nv!__gl_8f34971a", "" }, + { "nv!__gl_8f773984", "" }, + { "nv!__gl_8f7a7d", "" }, + { "nv!__gl_902486209", "" }, + { "nv!__gl_90482571", "" }, + { "nv!__gl_91214835", "" }, + { "nv!__gl_912848290", "" }, + { "nv!__gl_915e56", "" }, + { "nv!__gl_92179063", "" }, + { "nv!__gl_92179064", "" }, + { "nv!__gl_92179065", "" }, + { "nv!__gl_92179066", "" }, + { "nv!__gl_92350358", "" }, + { "nv!__gl_92809063", "" }, + { "nv!__gl_92809064", "" }, + { "nv!__gl_92809065", "" }, + { "nv!__gl_92809066", "" }, + { "nv!__gl_92920143", "" }, + { "nv!__gl_93a89b12", "" }, + { "nv!__gl_93a89c0b", "" }, + { "nv!__gl_94812574", "" }, + { "nv!__gl_95282304", "" }, + { "nv!__gl_95394027", "" }, + { "nv!__gl_959b1f", "" }, + { "nv!__gl_9638af", "" }, + { "nv!__gl_96fd59", "" }, + { "nv!__gl_97f6275666", "" }, + { "nv!__gl_97f6275667", "" }, + { "nv!__gl_97f6275668", "" }, + { "nv!__gl_97f6275669", "" }, + { "nv!__gl_97f627566a", "" }, + { "nv!__gl_97f627566b", "" }, + { "nv!__gl_97f627566d", "" }, + { "nv!__gl_97f627566e", "" }, + { "nv!__gl_97f627566f", "" }, + { "nv!__gl_97f6275670", "" }, + { "nv!__gl_97f6275671", "" }, + { "nv!__gl_97f727566e", "" }, + { "nv!__gl_98480775", "" }, + { "nv!__gl_98480776", "" }, + { "nv!__gl_98480777", "" }, + { "nv!__gl_992431", "" }, + { "nv!__gl_9aa29065", "" }, + { "nv!__gl_9af32c", "" }, + { "nv!__gl_9af32d", "" }, + { "nv!__gl_9af32e", "" }, + { "nv!__gl_9c108b71", "" }, + { "nv!__gl_9f279065", "" }, + { "nv!__gl_a01bc728", "" }, + { "nv!__gl_a13b46c80", "" }, + { "nv!__gl_a22eb0", "" }, + { "nv!__gl_a2fb451e", "" }, + { "nv!__gl_a3456abe", "" }, + { "nv!__gl_a7044887", "" }, + { "nv!__gl_a7149200", "" }, + { "nv!__gl_a766215670", "" }, + { "nv!__gl_aalinegamma", "" }, + { "nv!__gl_aalinetweaks", "" }, + { "nv!__gl_ab34ee01", "" }, + { "nv!__gl_ab34ee02", "" }, + { "nv!__gl_ab34ee03", "" }, + { "nv!__gl_ac0274", "" }, + { "nv!__gl_af73c63e", "" }, + { "nv!__gl_af73c63f", "" }, + { "nv!__gl_af9927", "" }, + { "nv!__gl_afoverride", "" }, + { "nv!__gl_allocdeviceevents", "" }, + { "nv!__gl_applicationkey", "" }, + { "nv!__gl_appreturnonlybasicglsltype", "" }, + { "nv!__gl_app_softimage", "" }, + { "nv!__gl_app_supportbits2", "" }, + { "nv!__gl_assumetextureismipmappedatcreation", "" }, + { "nv!__gl_b1fb0f01", "" }, + { "nv!__gl_b3edd5", "" }, + { "nv!__gl_b40d9e03d", "" }, + { "nv!__gl_b7f6275666", "" }, + { "nv!__gl_b812c1", "" }, + { "nv!__gl_ba14ba1a", "" }, + { "nv!__gl_ba14ba1b", "" }, + { "nv!__gl_bd7559", "" }, + { "nv!__gl_bd755a", "" }, + { "nv!__gl_bd755c", "" }, + { "nv!__gl_bd755d", "" }, + { "nv!__gl_be58bb", "" }, + { "nv!__gl_be92cb", "" }, + { "nv!__gl_beefcba3", "" }, + { "nv!__gl_beefcba4", "" }, + { "nv!__gl_c023777f", "" }, + { "nv!__gl_c09dc8", "" }, + { "nv!__gl_c0d340", "" }, + { "nv!__gl_c2ff374c", "" }, + { "nv!__gl_c5e9d7a3", "" }, + { "nv!__gl_c5e9d7a4", "" }, + { "nv!__gl_c5e9d7b4", "" }, + { "nv!__gl_c618f9", "" }, + { "nv!__gl_ca345840", "" }, + { "nv!__gl_cachedisable", "" }, + { "nv!__gl_channelpriorityoverride", "" }, + { "nv!__gl_cleardatastorevidmem", "" }, + { "nv!__gl_cmdbufmemoryspaceenables", "" }, + { "nv!__gl_cmdbufminwords", "" }, + { "nv!__gl_cmdbufsizewords", "" }, + { "nv!__gl_conformantblitframebufferscissor", "" }, + { "nv!__gl_conformantincompletetextures", "" }, + { "nv!__gl_copybuffermethod", "" }, + { "nv!__gl_cubemapaniso", "" }, + { "nv!__gl_cubemapfiltering", "" }, + { "nv!__gl_d0e9a4d7", "" }, + { "nv!__gl_d13733f12", "" }, + { "nv!__gl_d1b399", "" }, + { "nv!__gl_d2983c32", "" }, + { "nv!__gl_d2983c33", "" }, + { "nv!__gl_d2e71b", "" }, + { "nv!__gl_d377dc", "" }, + { "nv!__gl_d377dd", "" }, + { "nv!__gl_d489f4", "" }, + { "nv!__gl_d4bce1", "" }, + { "nv!__gl_d518cb", "" }, + { "nv!__gl_d518cd", "" }, + { "nv!__gl_d518ce", "" }, + { "nv!__gl_d518d0", "" }, + { "nv!__gl_d518d1", "" }, + { "nv!__gl_d518d2", "" }, + { "nv!__gl_d518d3", "" }, + { "nv!__gl_d518d4", "" }, + { "nv!__gl_d518d5", "" }, + { "nv!__gl_d59eda", "" }, + { "nv!__gl_d83cbd", "" }, + { "nv!__gl_d8e777", "" }, + { "nv!__gl_debug_level", "" }, + { "nv!__gl_debug_mask", "" }, + { "nv!__gl_debug_options", "" }, + { "nv!__gl_devshmpageableallocations", "" }, + { "nv!__gl_df1f9812", "" }, + { "nv!__gl_df783c", "" }, + { "nv!__gl_diagenable", "" }, + { "nv!__gl_disallowcemask", "" }, + { "nv!__gl_disallowz16", "" }, + { "nv!__gl_dlmemoryspaceenables", "" }, + { "nv!__gl_e0bfec", "" }, + { "nv!__gl_e433456d", "" }, + { "nv!__gl_e435563f", "" }, + { "nv!__gl_e4cd9c", "" }, + { "nv!__gl_e5c972", "" }, + { "nv!__gl_e639ef", "" }, + { "nv!__gl_e802af", "" }, + { "nv!__gl_eae964", "" }, + { "nv!__gl_earlytexturehwallocation", "" }, + { "nv!__gl_eb92a3", "" }, + { "nv!__gl_ebca56", "" }, + { "nv!__gl_expert_detail_level", "" }, + { "nv!__gl_expert_output_mask", "" }, + { "nv!__gl_expert_report_mask", "" }, + { "nv!__gl_extensionstringnvarch", "" }, + { "nv!__gl_extensionstringversion", "" }, + { "nv!__gl_f00f1938", "" }, + { "nv!__gl_f10736", "" }, + { "nv!__gl_f1846870", "" }, + { "nv!__gl_f33bc370", "" }, + { "nv!__gl_f392a874", "" }, + { "nv!__gl_f49ae8", "" }, + { "nv!__gl_fa345cce", "" }, + { "nv!__gl_fa35cc4", "" }, + { "nv!__gl_faa14a", "" }, + { "nv!__gl_faf8a723", "" }, + { "nv!__gl_fastgs", "" }, + { "nv!__gl_fbf4ac45", "" }, + { "nv!__gl_fbo_blit_ignore_srgb", "" }, + { "nv!__gl_fc64c7", "" }, + { "nv!__gl_ff54ec97", "" }, + { "nv!__gl_ff54ec98", "" }, + { "nv!__gl_forceexitprocessdetach", "" }, + { "nv!__gl_forcerequestedesversion", "" }, + { "nv!__gl_glsynctovblank", "" }, + { "nv!__gl_gvitimeoutcontrol", "" }, + { "nv!__gl_hcctrl", "" }, + { "nv!__gl_hwstate_per_ctx", "" }, + { "nv!__gl_machinecachelimit", "" }, + { "nv!__gl_maxframesallowed", "" }, + { "nv!__gl_memmgrcachedalloclimit", "" }, + { "nv!__gl_memmgrcachedalloclimitratio", "" }, + { "nv!__gl_memmgrsysheapalloclimit", "" }, + { "nv!__gl_memmgrsysheapalloclimitratio", "" }, + { "nv!__gl_memmgrvidheapalloclimit", "" }, + { "nv!__gl_mosaic_clip_to_subdev", "" }, + { "nv!__gl_mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!__gl_mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!__gl_overlaymergeblittimerms", "" }, + { "nv!__gl_perfmon_mode", "" }, + { "nv!__gl_pixbar_mode", "" }, + { "nv!__gl_qualityenhancements", "" }, + { "nv!__gl_r27s18q28", "" }, + { "nv!__gl_r2d7c1d8", "" }, + { "nv!__gl_renderer", "" }, + { "nv!__gl_renderqualityflags", "" }, + { "nv!__gl_s3tcquality", "" }, + { "nv!__gl_shaderatomics", "" }, + { "nv!__gl_shadercacheinitsize", "" }, + { "nv!__gl_shader_disk_cache_path", "" }, + { "nv!__gl_shader_disk_cache_read_only", "" }, + { "nv!__gl_shaderobjects", "" }, + { "nv!__gl_shaderportabilitywarnings", "" }, + { "nv!__gl_shaderwarningsaserrors", "" }, + { "nv!__gl_skiptexturehostcopies", "" }, + { "nv!__glslc_debug_level", "" }, + { "nv!__glslc_debug_mask", "" }, + { "nv!__glslc_debug_options", "" }, + { "nv!__glslc_debug_filename", "" }, + { "nv!__gl_sli_dli_control", "" }, + { "nv!__gl_sparsetexture", "" }, + { "nv!__gl_spinlooptimeout", "" }, + { "nv!__gl_sync_to_vblank", "" }, + { "nv!glsynctovblank", "" }, + { "nv!__gl_sysheapreuseratio", "" }, + { "nv!__gl_sysmemtexturepromotion", "" }, + { "nv!__gl_targetflushcount", "" }, + { "nv!__gl_tearingfreeswappresent", "" }, + { "nv!__gl_texclampbehavior", "" }, + { "nv!__gl_texlodbias", "" }, + { "nv!__gl_texmemoryspaceenables", "" }, + { "nv!__gl_textureprecache", "" }, + { "nv!__gl_threadcontrol", "" }, + { "nv!__gl_threadcontrol2", "" }, + { "nv!__gl_usegvievents", "" }, + { "nv!__gl_vbomemoryspaceenables", "" }, + { "nv!__gl_vertexlimit", "" }, + { "nv!__gl_vidheapreuseratio", "" }, + { "nv!__gl_vpipe", "" }, + { "nv!__gl_vpipeformatbloatlimit", "" }, + { "nv!__gl_wglmessageboxonabort", "" }, + { "nv!__gl_writeinfolog", "" }, + { "nv!__gl_writeprogramobjectassembly", "" }, + { "nv!__gl_writeprogramobjectsource", "" }, + { "nv!__gl_xnvadapterpresent", "" }, + { "nv!__gl_yield", "" }, + { "nv!__gl_yieldfunction", "" }, + { "nv!__gl_yieldfunctionfast", "" }, + { "nv!__gl_yieldfunctionslow", "" }, + { "nv!__gl_yieldfunctionwaitfordcqueue", "" }, + { "nv!__gl_yieldfunctionwaitforframe", "" }, + { "nv!__gl_yieldfunctionwaitforgpu", "" }, + { "nv!__gl_zbctableaddhysteresis", "" }, + { "nv!gpu_debug_mode", "" }, + { "nv!gpu_stay_on", "" }, + { "nv!gpu_timeout_ms_max", "" }, + { "nv!gvitimeoutcontrol", "" }, + { "nv!hcctrl", "" }, + { "nv!hwstate_per_ctx", "" }, + { "nv!libandroid_enable_log", "" }, + { "nv!machinecachelimit", "" }, + { "nv!maxframesallowed", "" }, + { "nv!media.aac_51_output_enabled", "" }, + { "nv!memmgrcachedalloclimit", "" }, + { "nv!memmgrcachedalloclimitratio", "" }, + { "nv!memmgrsysheapalloclimit", "" }, + { "nv!memmgrsysheapalloclimitratio", "" }, + { "nv!memmgrvidheapalloclimit", "" }, + { "nv!mosaic_clip_to_subdev", "" }, + { "nv!mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!nvblit.dump", "" }, + { "nv!nvblit.profile", "" }, + { "nv!nvblit.twod", "" }, + { "nv!nvblit.vic", "" }, + { "nv!nvddk_vic_prevent_use", "" }, + { "nv!nv_decompression", "" }, + { "nv!nvdisp_bl_ctrl", "0" }, + { "nv!nvdisp_debug_mask", "" }, + { "nv!nvdisp_enable_ts", "0" }, + { "nv!nvhdcp_timeout_ms", "12000" }, + { "nv!nvhdcp_max_retries", "5" }, + { "nv!nv_emc_dvfs_test", "" }, + { "nv!nv_emc_init_rate_hz", "" }, + { "nv!nv_gmmu_va_page_split", "" }, + { "nv!nv_gmmu_va_range", "" }, + { "nv!nvhost_debug_mask", "" }, + { "nv!nvidia.hwc.dump_config", "" }, + { "nv!nvidia.hwc.dump_layerlist", "" }, + { "nv!nvidia.hwc.dump_windows", "" }, + { "nv!nvidia.hwc.enable_disp_trans", "" }, + { "nv!nvidia.hwc.ftrace_enable", "" }, + { "nv!nvidia.hwc.hdcp_enable", "" }, + { "nv!nvidia.hwc.hidden_window_mask0", "" }, + { "nv!nvidia.hwc.hidden_window_mask1", "" }, + { "nv!nvidia.hwc.immediate_modeset", "" }, + { "nv!nvidia.hwc.imp_enable", "" }, + { "nv!nvidia.hwc.no_egl", "" }, + { "nv!nvidia.hwc.no_scratchblit", "" }, + { "nv!nvidia.hwc.no_vic", "" }, + { "nv!nvidia.hwc.null_display", "" }, + { "nv!nvidia.hwc.scan_props", "" }, + { "nv!nvidia.hwc.swap_interval", "" }, + { "nv!nvidia.hwc.war_1515812", "0" }, + { "nv!nvmap_debug_mask", "" }, + { "nv!nv_memory_profiler", "" }, + { "nv!nvnflinger_enable_log", "" }, + { "nv!nvnflinger_flip_policy", "" }, + { "nv!nvnflinger_hotplug_autoswitch", "0" }, + { "nv!nvnflinger_prefer_primary_layer", "0" }, + { "nv!nvnflinger_service_priority", "" }, + { "nv!nvnflinger_service_threads", "" }, + { "nv!nvnflinger_swap_interval", "" }, + { "nv!nvnflinger_track_perf", "" }, + { "nv!nvnflinger_virtualdisplay_policy", "60hz" }, + { "nv!nvn_no_vsync_capability", false }, + { "nv!nvn_through_opengl", "" }, + { "nv!nv_pllcx_always_on", "" }, + { "nv!nv_pllcx_safe_div", "" }, + { "nv!nvrm_gpu_channel_interleave", "" }, + { "nv!nvrm_gpu_channel_priority", "" }, + { "nv!nvrm_gpu_channel_timeslice", "" }, + { "nv!nvrm_gpu_default_device_index", "" }, + { "nv!nvrm_gpu_dummy", "" }, + { "nv!nvrm_gpu_help", "" }, + { "nv!nvrm_gpu_nvgpu_disable", "" }, + { "nv!nvrm_gpu_nvgpu_do_nfa_partial_map", "" }, + { "nv!nvrm_gpu_nvgpu_ecc_overrides", "" }, + { "nv!nvrm_gpu_nvgpu_no_as_get_va_regions", "" }, + { "nv!nvrm_gpu_nvgpu_no_channel_abort", "" }, + { "nv!nvrm_gpu_nvgpu_no_cyclestats", "" }, + { "nv!nvrm_gpu_nvgpu_no_fixed", "" }, + { "nv!nvrm_gpu_nvgpu_no_gpu_characteristics", "" }, + { "nv!nvrm_gpu_nvgpu_no_ioctl_mutex", "" }, + { "nv!nvrm_gpu_nvgpu_no_map_buffer_ex", "" }, + { "nv!nvrm_gpu_nvgpu_no_robustness", "" }, + { "nv!nvrm_gpu_nvgpu_no_sparse", "" }, + { "nv!nvrm_gpu_nvgpu_no_syncpoints", "" }, + { "nv!nvrm_gpu_nvgpu_no_tsg", "" }, + { "nv!nvrm_gpu_nvgpu_no_zbc", "" }, + { "nv!nvrm_gpu_nvgpu_no_zcull", "" }, + { "nv!nvrm_gpu_nvgpu_wrap_channels_in_tsgs", "" }, + { "nv!nvrm_gpu_prevent_use", "" }, + { "nv!nvrm_gpu_trace", "" }, + { "nv!nvsched_debug_mask", "" }, + { "nv!nvsched_force_enable", "" }, + { "nv!nvsched_force_log", "" }, + { "nv!nv_usb_plls_hw_ctrl", "" }, + { "nv!nv_winsys", "" }, + { "nv!nvwsi_dump", "" }, + { "nv!nvwsi_fill", "" }, + { "nv!ogl_", "" }, + { "nv!ogl_0356afd0", "" }, + { "nv!ogl_0356afd1", "" }, + { "nv!ogl_0356afd2", "" }, + { "nv!ogl_0356afd3", "" }, + { "nv!ogl_0x923dc0", "" }, + { "nv!ogl_0x923dc1", "" }, + { "nv!ogl_0x923dc2", "" }, + { "nv!ogl_0x923dc3", "" }, + { "nv!ogl_0x923dc4", "" }, + { "nv!ogl_0x923dd3", "" }, + { "nv!ogl_0x9abdc5", "" }, + { "nv!ogl_0x9abdc6", "" }, + { "nv!ogl_0xbd10fb", "" }, + { "nv!ogl_0xce2348", "" }, + { "nv!ogl_10261989", "" }, + { "nv!ogl_1042d483", "" }, + { "nv!ogl_10572898", "" }, + { "nv!ogl_115631", "" }, + { "nv!ogl_12950094", "" }, + { "nv!ogl_1314f311", "" }, + { "nv!ogl_1314f312", "" }, + { "nv!ogl_13279512", "" }, + { "nv!ogl_13813496", "" }, + { "nv!ogl_14507179", "" }, + { "nv!ogl_15694569", "" }, + { "nv!ogl_16936964", "" }, + { "nv!ogl_17aa230c", "" }, + { "nv!ogl_182054", "" }, + { "nv!ogl_18273275", "" }, + { "nv!ogl_18273276", "" }, + { "nv!ogl_1854d03b", "" }, + { "nv!ogl_18add00d", "" }, + { "nv!ogl_19156670", "" }, + { "nv!ogl_19286545", "" }, + { "nv!ogl_1a298e9f", "" }, + { "nv!ogl_1acf43fe", "" }, + { "nv!ogl_1bda43fe", "" }, + { "nv!ogl_1c3b92", "" }, + { "nv!ogl_21509920", "" }, + { "nv!ogl_215323457", "" }, + { "nv!ogl_2165ad", "" }, + { "nv!ogl_2165ae", "" }, + { "nv!ogl_21be9c", "" }, + { "nv!ogl_233264316", "" }, + { "nv!ogl_234557580", "" }, + { "nv!ogl_23cd0e", "" }, + { "nv!ogl_24189123", "" }, + { "nv!ogl_2443266", "" }, + { "nv!ogl_25025519", "" }, + { "nv!ogl_255e39", "" }, + { "nv!ogl_2583364", "" }, + { "nv!ogl_2888c1", "" }, + { "nv!ogl_28ca3e", "" }, + { "nv!ogl_29871243", "" }, + { "nv!ogl_2a1f64", "" }, + { "nv!ogl_2dc432", "" }, + { "nv!ogl_2de437", "" }, + { "nv!ogl_2f3bb89c", "" }, + { "nv!ogl_2fd652", "" }, + { "nv!ogl_3001ac", "" }, + { "nv!ogl_31298772", "" }, + { "nv!ogl_313233", "" }, + { "nv!ogl_31f7d603", "" }, + { "nv!ogl_320ce4", "" }, + { "nv!ogl_32153248", "" }, + { "nv!ogl_32153249", "" }, + { "nv!ogl_335bca", "" }, + { "nv!ogl_342abb", "" }, + { "nv!ogl_34dfe6", "" }, + { "nv!ogl_34dfe7", "" }, + { "nv!ogl_34dfe8", "" }, + { "nv!ogl_34dfe9", "" }, + { "nv!ogl_35201578", "" }, + { "nv!ogl_359278", "" }, + { "nv!ogl_37f53a", "" }, + { "nv!ogl_38144972", "" }, + { "nv!ogl_38542646", "" }, + { "nv!ogl_3b74c9", "" }, + { "nv!ogl_3c136f", "" }, + { "nv!ogl_3cf72823", "" }, + { "nv!ogl_3d7af029", "" }, + { "nv!ogl_3ff34782", "" }, + { "nv!ogl_4129618", "" }, + { "nv!ogl_4189fac3", "" }, + { "nv!ogl_420bd4", "" }, + { "nv!ogl_42a699", "" }, + { "nv!ogl_441369", "" }, + { "nv!ogl_4458713e", "" }, + { "nv!ogl_4554b6", "" }, + { "nv!ogl_457425", "" }, + { "nv!ogl_4603b207", "" }, + { "nv!ogl_46574957", "" }, + { "nv!ogl_46574958", "" }, + { "nv!ogl_46813529", "" }, + { "nv!ogl_46f1e13d", "" }, + { "nv!ogl_47534c43", "" }, + { "nv!ogl_48550336", "" }, + { "nv!ogl_48576893", "" }, + { "nv!ogl_48576894", "" }, + { "nv!ogl_4889ac02", "" }, + { "nv!ogl_49005740", "" }, + { "nv!ogl_49867584", "" }, + { "nv!ogl_49960973", "" }, + { "nv!ogl_4a5341", "" }, + { "nv!ogl_4f4e48", "" }, + { "nv!ogl_4f8a0a", "" }, + { "nv!ogl_50299698", "" }, + { "nv!ogl_50299699", "" }, + { "nv!ogl_50361291", "" }, + { "nv!ogl_5242ae", "" }, + { "nv!ogl_53d30c", "" }, + { "nv!ogl_56347a", "" }, + { "nv!ogl_563a95f1", "" }, + { "nv!ogl_573823", "" }, + { "nv!ogl_58027529", "" }, + { "nv!ogl_5d2d63", "" }, + { "nv!ogl_5f7e3b", "" }, + { "nv!ogl_60461793", "" }, + { "nv!ogl_60d355", "" }, + { "nv!ogl_616627aa", "" }, + { "nv!ogl_62317182", "" }, + { "nv!ogl_6253fa2e", "" }, + { "nv!ogl_64100768", "" }, + { "nv!ogl_64100769", "" }, + { "nv!ogl_64100770", "" }, + { "nv!ogl_647395", "" }, + { "nv!ogl_66543234", "" }, + { "nv!ogl_67674763", "" }, + { "nv!ogl_67739784", "" }, + { "nv!ogl_68fb9c", "" }, + { "nv!ogl_69801276", "" }, + { "nv!ogl_6af9fa2f", "" }, + { "nv!ogl_6af9fa3f", "" }, + { "nv!ogl_6af9fa4f", "" }, + { "nv!ogl_6bd8c7", "" }, + { "nv!ogl_6c7691", "" }, + { "nv!ogl_6d4296ce", "" }, + { "nv!ogl_6dd7e7", "" }, + { "nv!ogl_6dd7e8", "" }, + { "nv!ogl_6fe11ec1", "" }, + { "nv!ogl_716511763", "" }, + { "nv!ogl_72504593", "" }, + { "nv!ogl_73304097", "" }, + { "nv!ogl_73314098", "" }, + { "nv!ogl_74095213", "" }, + { "nv!ogl_74095213a", "" }, + { "nv!ogl_74095213b", "" }, + { "nv!ogl_74095214", "" }, + { "nv!ogl_748f9649", "" }, + { "nv!ogl_75494732", "" }, + { "nv!ogl_78452832", "" }, + { "nv!ogl_784561", "" }, + { "nv!ogl_78e16b9c", "" }, + { "nv!ogl_79251225", "" }, + { "nv!ogl_7c128b", "" }, + { "nv!ogl_7ccd93", "" }, + { "nv!ogl_7df8d1", "" }, + { "nv!ogl_800c2310", "" }, + { "nv!ogl_80546710", "" }, + { "nv!ogl_80772310", "" }, + { "nv!ogl_808ee280", "" }, + { "nv!ogl_81131154", "" }, + { "nv!ogl_81274457", "" }, + { "nv!ogl_8292291f", "" }, + { "nv!ogl_83498426", "" }, + { "nv!ogl_84993794", "" }, + { "nv!ogl_84995585", "" }, + { "nv!ogl_84a0a0", "" }, + { "nv!ogl_852142", "" }, + { "nv!ogl_85612309", "" }, + { "nv!ogl_85612310", "" }, + { "nv!ogl_85612311", "" }, + { "nv!ogl_85612312", "" }, + { "nv!ogl_8623ff27", "" }, + { "nv!ogl_87364952", "" }, + { "nv!ogl_87f6275666", "" }, + { "nv!ogl_886748", "" }, + { "nv!ogl_89894423", "" }, + { "nv!ogl_8ad8a75", "" }, + { "nv!ogl_8ad8ad00", "" }, + { "nv!ogl_8bb815", "" }, + { "nv!ogl_8bb817", "" }, + { "nv!ogl_8bb818", "" }, + { "nv!ogl_8bb819", "" }, + { "nv!ogl_8e640cd1", "" }, + { "nv!ogl_8f34971a", "" }, + { "nv!ogl_8f773984", "" }, + { "nv!ogl_8f7a7d", "" }, + { "nv!ogl_902486209", "" }, + { "nv!ogl_90482571", "" }, + { "nv!ogl_91214835", "" }, + { "nv!ogl_912848290", "" }, + { "nv!ogl_915e56", "" }, + { "nv!ogl_92179063", "" }, + { "nv!ogl_92179064", "" }, + { "nv!ogl_92179065", "" }, + { "nv!ogl_92179066", "" }, + { "nv!ogl_92350358", "" }, + { "nv!ogl_92809063", "" }, + { "nv!ogl_92809064", "" }, + { "nv!ogl_92809065", "" }, + { "nv!ogl_92809066", "" }, + { "nv!ogl_92920143", "" }, + { "nv!ogl_93a89b12", "" }, + { "nv!ogl_93a89c0b", "" }, + { "nv!ogl_94812574", "" }, + { "nv!ogl_95282304", "" }, + { "nv!ogl_95394027", "" }, + { "nv!ogl_959b1f", "" }, + { "nv!ogl_9638af", "" }, + { "nv!ogl_96fd59", "" }, + { "nv!ogl_97f6275666", "" }, + { "nv!ogl_97f6275667", "" }, + { "nv!ogl_97f6275668", "" }, + { "nv!ogl_97f6275669", "" }, + { "nv!ogl_97f627566a", "" }, + { "nv!ogl_97f627566b", "" }, + { "nv!ogl_97f627566d", "" }, + { "nv!ogl_97f627566e", "" }, + { "nv!ogl_97f627566f", "" }, + { "nv!ogl_97f6275670", "" }, + { "nv!ogl_97f6275671", "" }, + { "nv!ogl_97f727566e", "" }, + { "nv!ogl_98480775", "" }, + { "nv!ogl_98480776", "" }, + { "nv!ogl_98480777", "" }, + { "nv!ogl_992431", "" }, + { "nv!ogl_9aa29065", "" }, + { "nv!ogl_9af32c", "" }, + { "nv!ogl_9af32d", "" }, + { "nv!ogl_9af32e", "" }, + { "nv!ogl_9c108b71", "" }, + { "nv!ogl_9f279065", "" }, + { "nv!ogl_a01bc728", "" }, + { "nv!ogl_a13b46c80", "" }, + { "nv!ogl_a22eb0", "" }, + { "nv!ogl_a2fb451e", "" }, + { "nv!ogl_a3456abe", "" }, + { "nv!ogl_a7044887", "" }, + { "nv!ogl_a7149200", "" }, + { "nv!ogl_a766215670", "" }, + { "nv!ogl_aalinegamma", "" }, + { "nv!ogl_aalinetweaks", "" }, + { "nv!ogl_ab34ee01", "" }, + { "nv!ogl_ab34ee02", "" }, + { "nv!ogl_ab34ee03", "" }, + { "nv!ogl_ac0274", "" }, + { "nv!ogl_af73c63e", "" }, + { "nv!ogl_af73c63f", "" }, + { "nv!ogl_af9927", "" }, + { "nv!ogl_afoverride", "" }, + { "nv!ogl_allocdeviceevents", "" }, + { "nv!ogl_applicationkey", "" }, + { "nv!ogl_appreturnonlybasicglsltype", "" }, + { "nv!ogl_app_softimage", "" }, + { "nv!ogl_app_supportbits2", "" }, + { "nv!ogl_assumetextureismipmappedatcreation", "" }, + { "nv!ogl_b1fb0f01", "" }, + { "nv!ogl_b3edd5", "" }, + { "nv!ogl_b40d9e03d", "" }, + { "nv!ogl_b7f6275666", "" }, + { "nv!ogl_b812c1", "" }, + { "nv!ogl_ba14ba1a", "" }, + { "nv!ogl_ba14ba1b", "" }, + { "nv!ogl_bd7559", "" }, + { "nv!ogl_bd755a", "" }, + { "nv!ogl_bd755c", "" }, + { "nv!ogl_bd755d", "" }, + { "nv!ogl_be58bb", "" }, + { "nv!ogl_be92cb", "" }, + { "nv!ogl_beefcba3", "" }, + { "nv!ogl_beefcba4", "" }, + { "nv!ogl_c023777f", "" }, + { "nv!ogl_c09dc8", "" }, + { "nv!ogl_c0d340", "" }, + { "nv!ogl_c2ff374c", "" }, + { "nv!ogl_c5e9d7a3", "" }, + { "nv!ogl_c5e9d7a4", "" }, + { "nv!ogl_c5e9d7b4", "" }, + { "nv!ogl_c618f9", "" }, + { "nv!ogl_ca345840", "" }, + { "nv!ogl_cachedisable", "" }, + { "nv!ogl_channelpriorityoverride", "" }, + { "nv!ogl_cleardatastorevidmem", "" }, + { "nv!ogl_cmdbufmemoryspaceenables", "" }, + { "nv!ogl_cmdbufminwords", "" }, + { "nv!ogl_cmdbufsizewords", "" }, + { "nv!ogl_conformantblitframebufferscissor", "" }, + { "nv!ogl_conformantincompletetextures", "" }, + { "nv!ogl_copybuffermethod", "" }, + { "nv!ogl_cubemapaniso", "" }, + { "nv!ogl_cubemapfiltering", "" }, + { "nv!ogl_d0e9a4d7", "" }, + { "nv!ogl_d13733f12", "" }, + { "nv!ogl_d1b399", "" }, + { "nv!ogl_d2983c32", "" }, + { "nv!ogl_d2983c33", "" }, + { "nv!ogl_d2e71b", "" }, + { "nv!ogl_d377dc", "" }, + { "nv!ogl_d377dd", "" }, + { "nv!ogl_d489f4", "" }, + { "nv!ogl_d4bce1", "" }, + { "nv!ogl_d518cb", "" }, + { "nv!ogl_d518cd", "" }, + { "nv!ogl_d518ce", "" }, + { "nv!ogl_d518d0", "" }, + { "nv!ogl_d518d1", "" }, + { "nv!ogl_d518d2", "" }, + { "nv!ogl_d518d3", "" }, + { "nv!ogl_d518d4", "" }, + { "nv!ogl_d518d5", "" }, + { "nv!ogl_d59eda", "" }, + { "nv!ogl_d83cbd", "" }, + { "nv!ogl_d8e777", "" }, + { "nv!ogl_debug_level", "" }, + { "nv!ogl_debug_mask", "" }, + { "nv!ogl_debug_options", "" }, + { "nv!ogl_devshmpageableallocations", "" }, + { "nv!ogl_df1f9812", "" }, + { "nv!ogl_df783c", "" }, + { "nv!ogl_diagenable", "" }, + { "nv!ogl_disallowcemask", "" }, + { "nv!ogl_disallowz16", "" }, + { "nv!ogl_dlmemoryspaceenables", "" }, + { "nv!ogl_e0bfec", "" }, + { "nv!ogl_e433456d", "" }, + { "nv!ogl_e435563f", "" }, + { "nv!ogl_e4cd9c", "" }, + { "nv!ogl_e5c972", "" }, + { "nv!ogl_e639ef", "" }, + { "nv!ogl_e802af", "" }, + { "nv!ogl_eae964", "" }, + { "nv!ogl_earlytexturehwallocation", "" }, + { "nv!ogl_eb92a3", "" }, + { "nv!ogl_ebca56", "" }, + { "nv!ogl_expert_detail_level", "" }, + { "nv!ogl_expert_output_mask", "" }, + { "nv!ogl_expert_report_mask", "" }, + { "nv!ogl_extensionstringnvarch", "" }, + { "nv!ogl_extensionstringversion", "" }, + { "nv!ogl_f00f1938", "" }, + { "nv!ogl_f10736", "" }, + { "nv!ogl_f1846870", "" }, + { "nv!ogl_f33bc370", "" }, + { "nv!ogl_f392a874", "" }, + { "nv!ogl_f49ae8", "" }, + { "nv!ogl_fa345cce", "" }, + { "nv!ogl_fa35cc4", "" }, + { "nv!ogl_faa14a", "" }, + { "nv!ogl_faf8a723", "" }, + { "nv!ogl_fastgs", "" }, + { "nv!ogl_fbf4ac45", "" }, + { "nv!ogl_fbo_blit_ignore_srgb", "" }, + { "nv!ogl_fc64c7", "" }, + { "nv!ogl_ff54ec97", "" }, + { "nv!ogl_ff54ec98", "" }, + { "nv!ogl_forceexitprocessdetach", "" }, + { "nv!ogl_forcerequestedesversion", "" }, + { "nv!ogl_glsynctovblank", "" }, + { "nv!ogl_gvitimeoutcontrol", "" }, + { "nv!ogl_hcctrl", "" }, + { "nv!ogl_hwstate_per_ctx", "" }, + { "nv!ogl_machinecachelimit", "" }, + { "nv!ogl_maxframesallowed", "" }, + { "nv!ogl_memmgrcachedalloclimit", "" }, + { "nv!ogl_memmgrcachedalloclimitratio", "" }, + { "nv!ogl_memmgrsysheapalloclimit", "" }, + { "nv!ogl_memmgrsysheapalloclimitratio", "" }, + { "nv!ogl_memmgrvidheapalloclimit", "" }, + { "nv!ogl_mosaic_clip_to_subdev", "" }, + { "nv!ogl_mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!ogl_mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!ogl_overlaymergeblittimerms", "" }, + { "nv!ogl_perfmon_mode", "" }, + { "nv!ogl_pixbar_mode", "" }, + { "nv!ogl_qualityenhancements", "" }, + { "nv!ogl_r27s18q28", "" }, + { "nv!ogl_r2d7c1d8", "" }, + { "nv!ogl_renderer", "" }, + { "nv!ogl_renderqualityflags", "" }, + { "nv!ogl_s3tcquality", "" }, + { "nv!ogl_shaderatomics", "" }, + { "nv!ogl_shadercacheinitsize", "" }, + { "nv!ogl_shader_disk_cache_path", "" }, + { "nv!ogl_shader_disk_cache_read_only", "" }, + { "nv!ogl_shaderobjects", "" }, + { "nv!ogl_shaderportabilitywarnings", "" }, + { "nv!ogl_shaderwarningsaserrors", "" }, + { "nv!ogl_skiptexturehostcopies", "" }, + { "nv!ogl_sli_dli_control", "" }, + { "nv!ogl_sparsetexture", "" }, + { "nv!ogl_spinlooptimeout", "" }, + { "nv!ogl_sync_to_vblank", "" }, + { "nv!ogl_sysheapreuseratio", "" }, + { "nv!ogl_sysmemtexturepromotion", "" }, + { "nv!ogl_targetflushcount", "" }, + { "nv!ogl_tearingfreeswappresent", "" }, + { "nv!ogl_texclampbehavior", "" }, + { "nv!ogl_texlodbias", "" }, + { "nv!ogl_texmemoryspaceenables", "" }, + { "nv!ogl_textureprecache", "" }, + { "nv!ogl_threadcontrol", "" }, + { "nv!ogl_threadcontrol2", "" }, + { "nv!ogl_usegvievents", "" }, + { "nv!ogl_vbomemoryspaceenables", "" }, + { "nv!ogl_vertexlimit", "" }, + { "nv!ogl_vidheapreuseratio", "" }, + { "nv!ogl_vpipe", "" }, + { "nv!ogl_vpipeformatbloatlimit", "" }, + { "nv!ogl_wglmessageboxonabort", "" }, + { "nv!ogl_writeinfolog", "" }, + { "nv!ogl_writeprogramobjectassembly", "" }, + { "nv!ogl_writeprogramobjectsource", "" }, + { "nv!ogl_xnvadapterpresent", "" }, + { "nv!ogl_yield", "" }, + { "nv!ogl_yieldfunction", "" }, + { "nv!ogl_yieldfunctionfast", "" }, + { "nv!ogl_yieldfunctionslow", "" }, + { "nv!ogl_yieldfunctionwaitfordcqueue", "" }, + { "nv!ogl_yieldfunctionwaitforframe", "" }, + { "nv!ogl_yieldfunctionwaitforgpu", "" }, + { "nv!ogl_zbctableaddhysteresis", "" }, + { "nv!overlaymergeblittimerms", "" }, + { "nv!perfmon_mode", "" }, + { "nv!persist.sys.display.resolution", "" }, + { "nv!persist.tegra.composite.fallb", "" }, + { "nv!persist.tegra.composite.policy", "" }, + { "nv!persist.tegra.composite.range", "" }, + { "nv!persist.tegra.compositor", "" }, + { "nv!persist.tegra.compositor.virt", "" }, + { "nv!persist.tegra.compression", "" }, + { "nv!persist.tegra.cursor.enable", "" }, + { "nv!persist.tegra.didim.enable", "" }, + { "nv!persist.tegra.didim.normal", "" }, + { "nv!persist.tegra.didim.video", "" }, + { "nv!persist.tegra.disp.heads", "" }, + { "nv!persist.tegra.gamma_correction", "" }, + { "nv!persist.tegra.gpu_mapping_cache", "" }, + { "nv!persist.tegra.grlayout", "" }, + { "nv!persist.tegra.hdmi.2020.10", "" }, + { "nv!persist.tegra.hdmi.2020.fake", "" }, + { "nv!persist.tegra.hdmi.2020.force", "" }, + { "nv!persist.tegra.hdmi.autorotate", "" }, + { "nv!persist.tegra.hdmi.hdr.fake", "" }, + { "nv!persist.tegra.hdmi.ignore_ratio", "" }, + { "nv!persist.tegra.hdmi.limit.clock", "" }, + { "nv!persist.tegra.hdmi.only_16_9", "" }, + { "nv!persist.tegra.hdmi.range", "" }, + { "nv!persist.tegra.hdmi.resolution", "" }, + { "nv!persist.tegra.hdmi.underscan", "" }, + { "nv!persist.tegra.hdmi.yuv.422", "" }, + { "nv!persist.tegra.hdmi.yuv.444", "" }, + { "nv!persist.tegra.hdmi.yuv.enable", "" }, + { "nv!persist.tegra.hdmi.yuv.force", "" }, + { "nv!persist.tegra.hwc.nvdc", "" }, + { "nv!persist.tegra.idle.minimum_fps", "" }, + { "nv!persist.tegra.panel.rotation", "" }, + { "nv!persist.tegra.scan_props", "" }, + { "nv!persist.tegra.stb.mode", "" }, + { "nv!persist.tegra.zbc_override", "" }, + { "nv!pixbar_mode", "" }, + { "nv!qualityenhancements", "" }, + { "nv!r27s18q28", "" }, + { "nv!r2d7c1d8", "" }, + { "nv!renderer", "" }, + { "nv!renderqualityflags", "" }, + { "nv!rmos_debug_mask", "" }, + { "nv!rmos_set_production_mode", "" }, + { "nv!s3tcquality", "" }, + { "nv!shaderatomics", "" }, + { "nv!shadercacheinitsize", "" }, + { "nv!shader_disk_cache_path", "" }, + { "nv!shader_disk_cache_read_only", "" }, + { "nv!shaderobjects", "" }, + { "nv!shaderportabilitywarnings", "" }, + { "nv!shaderwarningsaserrors", "" }, + { "nv!skiptexturehostcopies", "" }, + { "nv!sli_dli_control", "" }, + { "nv!sparsetexture", "" }, + { "nv!spinlooptimeout", "" }, + { "nv!sync_to_vblank", "" }, + { "nv!sysheapreuseratio", "" }, + { "nv!sysmemtexturepromotion", "" }, + { "nv!targetflushcount", "" }, + { "nv!tearingfreeswappresent", "" }, + { "nv!tegra.refresh", "" }, + { "nv!texclampbehavior", "" }, + { "nv!texlodbias", "" }, + { "nv!texmemoryspaceenables", "" }, + { "nv!textureprecache", "" }, + { "nv!threadcontrol", "" }, + { "nv!threadcontrol2", "" }, + { "nv!tvmr.avp.logs", "" }, + { "nv!tvmr.buffer.logs", "" }, + { "nv!tvmr.dec.prof", "" }, + { "nv!tvmr.deint.logs", "" }, + { "nv!tvmr.dfs.logs", "" }, + { "nv!tvmr.ffprof.logs", "" }, + { "nv!tvmr.game.stream", "" }, + { "nv!tvmr.general.logs", "" }, + { "nv!tvmr.input.dump", "" }, + { "nv!tvmr.seeking.logs", "" }, + { "nv!tvmr.ts_pulldown", "" }, + { "nv!usegvievents", "" }, + { "nv!vbomemoryspaceenables", "" }, + { "nv!vcc_debug_ip", "" }, + { "nv!vcc_verbose_level", "" }, + { "nv!vertexlimit", "" }, + { "nv!viccomposer.filter", "" }, + { "nv!videostats-enable", "" }, + { "nv!vidheapreuseratio", "" }, + { "nv!vpipe", "" }, + { "nv!vpipeformatbloatlimit", "" }, + { "nv!wglmessageboxonabort", "" }, + { "nv!writeinfolog", "" }, + { "nv!writeprogramobjectassembly", "" }, + { "nv!writeprogramobjectsource", "" }, + { "nv!xnvadapterpresent", "" }, + { "nv!yield", "" }, + { "nv!yieldfunction", "" }, + { "nv!yieldfunctionfast", "" }, + { "nv!yieldfunctionslow", "" }, + { "nv!yieldfunctionwaitfordcqueue", "" }, + { "nv!yieldfunctionwaitforframe", "" }, + { "nv!yieldfunctionwaitforgpu", "" }, + { "nv!zbctableaddhysteresis", "" }, + { "pcm!enable", true }, + { "pctl!intermittent_task_interval_seconds", 21600 }, + { "prepo!devmenu_prepo_page_view", false }, + { "prepo!background_processing", true }, + { "prepo!transmission_interval_min", 10 }, + { "prepo!transmission_retry_interval", 3600 }, + { "psm!evaluation_log_enabled", false }, + { "snap_shot_dump!auto_dump", false }, + { "snap_shot_dump!output_dir", "%USERPROFILE%/Documents/Nintendo/NXDMP" }, + { "snap_shot_dump!full_dump", false }, + { "systemconfig!field_testing", false }, + { "systemconfig!exhivision", false }, + { "systempowerstate!always_reboot", false }, + { "systempowerstate!power_state_message_emulation_trigger_time", 0 }, + { "systempowerstate!power_state_message_to_emulate", 0 }, + { "target_manager!device_name", "" }, + { "vulnerability!needs_update_vulnerability_policy", 0 }, + { "apm!performance_mode_policy", "auto" }, + { "apm!sdev_throttling_enabled", true }, + { "apm!sdev_throttling_additional_delay_us", 16000 }, + { "apm!battery_draining_enabled", false }, + { "apm!sdev_cpu_overclock_enabled", false }, + { "bcat!production_mode", true }, + { "bpc!enable_quasi_off", true }, + { "bsp0!usb", "UDS" }, + { "bsp0!tm_transport", "USB" }, + { "bluetooth_debug!skip_boot", false }, + { "contents_delivery!enable_debug_api", false }, + { "eupld!upload_enabled", true }, + { "fatal!transition_to_fatal", true }, + { "fatal!show_extra_info", false }, + { "gpu_core_dump!auto_dump", false }, + { "hid_debug!enables_debugpad", false }, + { "hid_debug!manages_devices", true }, + { "hid_debug!emulate_future_device", false }, + { "hid_debug!emulate_firmware_update_failure", false }, + { "hid_debug!emulate_mcu_hardware_error", false }, + { "hid_debug!firmware_update_failure_emulation_mode", 0 }, + { "jit_debug!enable_jit_debug", false }, + { "npns!background_processing", true }, + { "npns!logmanager_redirection", true }, + { "npns!sleep_processing_timeout", 30 }, + { "npns!sleep_periodic_interval", 10800 }, + { "npns!sleep_max_try_count", 5 }, + { "npns!test_mode", false }, + { "ns.applet!overlay_applet_id", "0x010000000000100c" }, + { "ns.applet!system_applet_id", "0x0100000000001000" }, + { "ns.applet!shop_applet_id", "0x010000000000100b" }, + { "ns.autoboot!enabled", true }, + { "ns.pseudodeviceid!reset_pseudo_device_id", false }, + { "nsd!environment_identifier", "lp1" }, + { "nsd!test_mode", false }, + { "ntc!is_autonomic_correction_enabled", true }, + { "ntc!autonomic_correction_interval_seconds", 432000 }, + { "ntc!autonomic_correction_failed_retry_interval_seconds", 1800 }, + { "ntc!autonomic_correction_immediate_try_count_max", 4 }, + { "ntc!autonomic_correction_immediate_try_interval_milliseconds", 5000 }, + { "nv!nv_graphics_firmware_memory_margin", false }, + { "omm!operation_mode_policy", "auto" }, + { "omm!sleep_fade_in_ms", 50 }, + { "omm!sleep_fade_out_ms", 100 }, + { "omm!charging_sign_ms", 3000 }, + { "omm!low_battery_sign_ms", 3000 }, + { "omm!sign_fade_in_ms", 0 }, + { "omm!sign_fade_out_ms", 400 }, + { "omm!sign_wait_layer_visible_ms", 100 }, + { "omm!startup_fade_in_ms", 200 }, + { "omm!startup_fade_out_ms", 400 }, + { "omm!backlight_off_ms_on_handheld_switch", 150 }, + { "omm!sleep_on_ac_ok_boot", true }, + { "pdm!save_playlog", true }, + { "productinfo!product_name", "Nintendo Switch" }, + { "productinfo!cec_osd_name", "NintendoSwitch" }, + { "ro!ease_nro_restriction", false }, + { "settings_debug!is_debug_mode_enabled", false }, + { "systemreport!enabled", true }, + { "systemsleep!enter_sleep", true }, + { "systemsleep!enter_sc7", true }, + { "systemsleep!keep_vdd_core", true }, + { "systemsleep!disable_tma_sleep", false }, + { "systemsleep!disable_auto_sleep", false }, + { "systemsleep!override_auto_sleep_time", 0 }, + { "systemsleep!sleep_pending_time_ms", 15000 }, + { "systemsleep!hush_time_after_brief_power_button_press_ms", 1000 }, + { "systemsleep!transition_timeout_sec", 60 }, + { "systemsleep!dummy_event_auto_wake", false }, + { "systemupdate!debug_id", "0x0000000000000000" }, + { "systemupdate!debug_version", 0 }, + { "systemupdate!bgnup_retry_seconds", 60 }, + { "systemupdate!enable_background_download_stress_testing", false }, + { "systemupdate!debug_id_for_content_delivery", "0x0000000000000000" }, + { "systemupdate!debug_version_for_content_delivery", 0 }, + { "systemupdate!assumed_system_applet_version", 0 }, + { "tc!iir_filter_gain_soc", 100 }, + { "tc!iir_filter_gain_pcb", 100 }, + { "tc!tskin_soc_coefficients_handheld", "[5464, 174190]" }, + { "tc!tskin_soc_coefficients_console", "[6182, 112480]" }, + { "tc!tskin_pcb_coefficients_handheld", "[5464, 174190]" }, + { "tc!tskin_pcb_coefficients_console", "[6182, 112480]" }, + { "tc!tskin_select", "both" }, + { "tc!tskin_rate_table_handheld", "[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 48000, 51, 102], [48000, 53000, 102, 153], [53000, 1000000, 153, 153], [48000, 1000000, 153, 153]]" }, + { "tc!tskin_rate_table_console", "[[-1000000, 43000, 51, 51], [43000, 53000, 51, 153], [53000, 58000, 153, 255], [58000, 1000000, 255, 255]]" }, + { "tc!rate_select", "both" }, + { "tc!log_enabled", false }, + { "tc!sleep_enabled", true }, + { "time!standard_steady_clock_test_offset_minutes", 0 }, + { "time!standard_steady_clock_rtc_update_interval_minutes", 5 }, + { "time!standard_network_clock_sufficient_accuracy_minutes", 43200 }, + { "usb!usb30_force_enabled", false }, + { "wlan_debug!skip_wlan_boot", false } + }; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Settings/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Settings/ResultCode.cs new file mode 100644 index 00000000..6d4d578f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Settings/ResultCode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Settings +{ + enum ResultCode + { + ModuleId = 105, + ErrorCodeShift = 9, + + Success = 0, + + LanguageOutOfRange = (625 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sfdnsres/GaiError.cs b/Ryujinx.HLE/HOS/Services/Sfdnsres/GaiError.cs deleted file mode 100644 index dc724b4d..00000000 --- a/Ryujinx.HLE/HOS/Services/Sfdnsres/GaiError.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Sfdnsres -{ - enum GaiError - { - Success, - AddressFamily, - Again, - BadFlags, - Fail, - Family, - Memory, - NoData, - NoName, - Service, - SocketType, - System, - BadHints, - Protocol, - Overflow, - Max - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs b/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs deleted file mode 100644 index 0e42ee3b..00000000 --- a/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs +++ /dev/null @@ -1,387 +0,0 @@ -using Ryujinx.Common.Logging; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Sfdnsres -{ - [Service("sfdnsres")] - class IResolver : IpcService - { - public IResolver(ServiceCtx context) { } - - private long SerializeHostEnt(ServiceCtx context, IPHostEntry hostEntry, List addresses = null) - { - long originalBufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferPosition = originalBufferPosition; - long bufferSize = context.Request.ReceiveBuff[0].Size; - - string hostName = hostEntry.HostName + '\0'; - - // h_name - context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(hostName)); - bufferPosition += hostName.Length; - - // h_aliases list size - context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(hostEntry.Aliases.Length)); - bufferPosition += 4; - - // Actual aliases - foreach (string alias in hostEntry.Aliases) - { - context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(alias + '\0')); - bufferPosition += alias.Length + 1; - } - - // h_addrtype but it's a short (also only support IPv4) - context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)2)); - bufferPosition += 2; - - // h_length but it's a short - context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)4)); - bufferPosition += 2; - - // Ip address count, we can only support ipv4 (blame Nintendo) - context.Memory.WriteInt32(bufferPosition, addresses != null ? IPAddress.HostToNetworkOrder(addresses.Count) : 0); - bufferPosition += 4; - - if (addresses != null) - { - foreach (IPAddress ip in addresses) - { - context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(BitConverter.ToInt32(ip.GetAddressBytes(), 0))); - bufferPosition += 4; - } - } - - return bufferPosition - originalBufferPosition; - } - - private string GetGaiStringErrorFromErrorCode(GaiError errorCode) - { - if (errorCode > GaiError.Max) - { - errorCode = GaiError.Max; - } - - switch (errorCode) - { - case GaiError.AddressFamily: - return "Address family for hostname not supported"; - case GaiError.Again: - return "Temporary failure in name resolution"; - case GaiError.BadFlags: - return "Invalid value for ai_flags"; - case GaiError.Fail: - return "Non-recoverable failure in name resolution"; - case GaiError.Family: - return "ai_family not supported"; - case GaiError.Memory: - return "Memory allocation failure"; - case GaiError.NoData: - return "No address associated with hostname"; - case GaiError.NoName: - return "hostname nor servname provided, or not known"; - case GaiError.Service: - return "servname not supported for ai_socktype"; - case GaiError.SocketType: - return "ai_socktype not supported"; - case GaiError.System: - return "System error returned in errno"; - case GaiError.BadHints: - return "Invalid value for hints"; - case GaiError.Protocol: - return "Resolved protocol is unknown"; - case GaiError.Overflow: - return "Argument buffer overflow"; - case GaiError.Max: - return "Unknown error"; - default: - return "Success"; - } - } - - private string GetHostStringErrorFromErrorCode(NetDbError errorCode) - { - if (errorCode <= NetDbError.Internal) - { - return "Resolver internal error"; - } - - switch (errorCode) - { - case NetDbError.Success: - return "Resolver Error 0 (no error)"; - case NetDbError.HostNotFound: - return "Unknown host"; - case NetDbError.TryAgain: - return "Host name lookup failure"; - case NetDbError.NoRecovery: - return "Unknown server error"; - case NetDbError.NoData: - return "No address associated with name"; - default: - return "Unknown resolver error"; - } - } - - private List GetIpv4Addresses(IPHostEntry hostEntry) - { - List result = new List(); - foreach (IPAddress ip in hostEntry.AddressList) - { - if (ip.AddressFamily == AddressFamily.InterNetwork) - result.Add(ip); - } - return result; - } - - [Command(0)] - // SetDnsAddressesPrivate(u32, buffer) - public ResultCode SetDnsAddressesPrivate(ServiceCtx context) - { - uint unknown0 = context.RequestData.ReadUInt32(); - long bufferPosition = context.Request.SendBuff[0].Position; - long bufferSize = context.Request.SendBuff[0].Size; - - // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness. - Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); - - return ResultCode.NotAllocated; - } - - [Command(1)] - // GetDnsAddressPrivate(u32) -> buffer - public ResultCode GetDnsAddressesPrivate(ServiceCtx context) - { - uint unknown0 = context.RequestData.ReadUInt32(); - - // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness. - Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); - - return ResultCode.NotAllocated; - } - - [Command(2)] - // GetHostByName(u8, u32, u64, pid, buffer) -> (u32, u32, u32, buffer) - public ResultCode GetHostByName(ServiceCtx context) - { - byte[] rawName = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size); - string name = Encoding.ASCII.GetString(rawName).TrimEnd('\0'); - - // TODO: use params - bool enableNsdResolve = context.RequestData.ReadInt32() == 1; - int timeOut = context.RequestData.ReadInt32(); - ulong pidPlaceholder = context.RequestData.ReadUInt64(); - - IPHostEntry hostEntry = null; - - NetDbError netDbErrorCode = NetDbError.Success; - GaiError errno = GaiError.Overflow; - long serializedSize = 0; - - if (name.Length <= 255) - { - try - { - hostEntry = Dns.GetHostEntry(name); - } - catch (SocketException exception) - { - netDbErrorCode = NetDbError.Internal; - - if (exception.ErrorCode == 11001) - { - netDbErrorCode = NetDbError.HostNotFound; - errno = GaiError.NoData; - } - else if (exception.ErrorCode == 11002) - { - netDbErrorCode = NetDbError.TryAgain; - } - else if (exception.ErrorCode == 11003) - { - netDbErrorCode = NetDbError.NoRecovery; - } - else if (exception.ErrorCode == 11004) - { - netDbErrorCode = NetDbError.NoData; - } - else if (exception.ErrorCode == 10060) - { - errno = GaiError.Again; - } - } - } - else - { - netDbErrorCode = NetDbError.HostNotFound; - } - - if (hostEntry != null) - { - errno = GaiError.Success; - - List addresses = GetIpv4Addresses(hostEntry); - - if (addresses.Count == 0) - { - errno = GaiError.NoData; - netDbErrorCode = NetDbError.NoAddress; - } - else - { - serializedSize = SerializeHostEnt(context, hostEntry, addresses); - } - } - - context.ResponseData.Write((int)netDbErrorCode); - context.ResponseData.Write((int)errno); - context.ResponseData.Write(serializedSize); - - return ResultCode.Success; - } - - [Command(3)] - // GetHostByAddr(u32, u32, u32, u64, pid, buffer) -> (u32, u32, u32, buffer) - public ResultCode GetHostByAddress(ServiceCtx context) - { - byte[] rawIp = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size); - - // TODO: use params - uint socketLength = context.RequestData.ReadUInt32(); - uint type = context.RequestData.ReadUInt32(); - int timeOut = context.RequestData.ReadInt32(); - ulong pidPlaceholder = context.RequestData.ReadUInt64(); - - IPHostEntry hostEntry = null; - - NetDbError netDbErrorCode = NetDbError.Success; - GaiError errno = GaiError.AddressFamily; - long serializedSize = 0; - - if (rawIp.Length == 4) - { - try - { - IPAddress address = new IPAddress(rawIp); - - hostEntry = Dns.GetHostEntry(address); - } - catch (SocketException exception) - { - netDbErrorCode = NetDbError.Internal; - if (exception.ErrorCode == 11001) - { - netDbErrorCode = NetDbError.HostNotFound; - errno = GaiError.NoData; - } - else if (exception.ErrorCode == 11002) - { - netDbErrorCode = NetDbError.TryAgain; - } - else if (exception.ErrorCode == 11003) - { - netDbErrorCode = NetDbError.NoRecovery; - } - else if (exception.ErrorCode == 11004) - { - netDbErrorCode = NetDbError.NoData; - } - else if (exception.ErrorCode == 10060) - { - errno = GaiError.Again; - } - } - } - else - { - netDbErrorCode = NetDbError.NoAddress; - } - - if (hostEntry != null) - { - errno = GaiError.Success; - serializedSize = SerializeHostEnt(context, hostEntry, GetIpv4Addresses(hostEntry)); - } - - context.ResponseData.Write((int)netDbErrorCode); - context.ResponseData.Write((int)errno); - context.ResponseData.Write(serializedSize); - - return ResultCode.Success; - } - - [Command(4)] - // GetHostStringError(u32) -> buffer - public ResultCode GetHostStringError(ServiceCtx context) - { - ResultCode resultCode = ResultCode.NotAllocated; - NetDbError errorCode = (NetDbError)context.RequestData.ReadInt32(); - string errorString = GetHostStringErrorFromErrorCode(errorCode); - - if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size) - { - resultCode = 0; - context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0')); - } - - return resultCode; - } - - [Command(5)] - // GetGaiStringError(u32) -> buffer - public ResultCode GetGaiStringError(ServiceCtx context) - { - ResultCode resultCode = ResultCode.NotAllocated; - GaiError errorCode = (GaiError)context.RequestData.ReadInt32(); - string errorString = GetGaiStringErrorFromErrorCode(errorCode); - - if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size) - { - resultCode = 0; - context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0')); - } - - return resultCode; - } - - [Command(8)] - // RequestCancelHandle(u64, pid) -> u32 - public ResultCode RequestCancelHandle(ServiceCtx context) - { - ulong unknown0 = context.RequestData.ReadUInt64(); - - context.ResponseData.Write(0); - - Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); - - return ResultCode.Success; - } - - [Command(9)] - // CancelSocketCall(u32, u64, pid) - public ResultCode CancelSocketCall(ServiceCtx context) - { - uint unknown0 = context.RequestData.ReadUInt32(); - ulong unknown1 = context.RequestData.ReadUInt64(); - - Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0, unknown1 }); - - return ResultCode.Success; - } - - [Command(11)] - // ClearDnsAddresses(u32) - public ResultCode ClearDnsAddresses(ServiceCtx context) - { - uint unknown0 = context.RequestData.ReadUInt32(); - - Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sfdnsres/NetDBError.cs b/Ryujinx.HLE/HOS/Services/Sfdnsres/NetDBError.cs deleted file mode 100644 index 95ef7419..00000000 --- a/Ryujinx.HLE/HOS/Services/Sfdnsres/NetDBError.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Sfdnsres -{ - enum NetDbError - { - Internal = -1, - Success, - HostNotFound, - TryAgain, - NoRecovery, - NoData, - NoAddress = NoData - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sm/IManagerInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IManagerInterface.cs new file mode 100644 index 00000000..f867f23a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sm/IManagerInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sm +{ + [Service("sm:m")] + class IManagerInterface : IpcService + { + public IManagerInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs new file mode 100644 index 00000000..3a02e06c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs @@ -0,0 +1,1180 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +{ + [Service("bsd:s", true)] + [Service("bsd:u", false)] + class IClient : IpcService + { + private static Dictionary _errorMap = new Dictionary + { + // WSAEINTR + {WsaError.WSAEINTR, LinuxError.EINTR}, + // WSAEWOULDBLOCK + {WsaError.WSAEWOULDBLOCK, LinuxError.EWOULDBLOCK}, + // WSAEINPROGRESS + {WsaError.WSAEINPROGRESS, LinuxError.EINPROGRESS}, + // WSAEALREADY + {WsaError.WSAEALREADY, LinuxError.EALREADY}, + // WSAENOTSOCK + {WsaError.WSAENOTSOCK, LinuxError.ENOTSOCK}, + // WSAEDESTADDRREQ + {WsaError.WSAEDESTADDRREQ, LinuxError.EDESTADDRREQ}, + // WSAEMSGSIZE + {WsaError.WSAEMSGSIZE, LinuxError.EMSGSIZE}, + // WSAEPROTOTYPE + {WsaError.WSAEPROTOTYPE, LinuxError.EPROTOTYPE}, + // WSAENOPROTOOPT + {WsaError.WSAENOPROTOOPT, LinuxError.ENOPROTOOPT}, + // WSAEPROTONOSUPPORT + {WsaError.WSAEPROTONOSUPPORT, LinuxError.EPROTONOSUPPORT}, + // WSAESOCKTNOSUPPORT + {WsaError.WSAESOCKTNOSUPPORT, LinuxError.ESOCKTNOSUPPORT}, + // WSAEOPNOTSUPP + {WsaError.WSAEOPNOTSUPP, LinuxError.EOPNOTSUPP}, + // WSAEPFNOSUPPORT + {WsaError.WSAEPFNOSUPPORT, LinuxError.EPFNOSUPPORT}, + // WSAEAFNOSUPPORT + {WsaError.WSAEAFNOSUPPORT, LinuxError.EAFNOSUPPORT}, + // WSAEADDRINUSE + {WsaError.WSAEADDRINUSE, LinuxError.EADDRINUSE}, + // WSAEADDRNOTAVAIL + {WsaError.WSAEADDRNOTAVAIL, LinuxError.EADDRNOTAVAIL}, + // WSAENETDOWN + {WsaError.WSAENETDOWN, LinuxError.ENETDOWN}, + // WSAENETUNREACH + {WsaError.WSAENETUNREACH, LinuxError.ENETUNREACH}, + // WSAENETRESET + {WsaError.WSAENETRESET, LinuxError.ENETRESET}, + // WSAECONNABORTED + {WsaError.WSAECONNABORTED, LinuxError.ECONNABORTED}, + // WSAECONNRESET + {WsaError.WSAECONNRESET, LinuxError.ECONNRESET}, + // WSAENOBUFS + {WsaError.WSAENOBUFS, LinuxError.ENOBUFS}, + // WSAEISCONN + {WsaError.WSAEISCONN, LinuxError.EISCONN}, + // WSAENOTCONN + {WsaError.WSAENOTCONN, LinuxError.ENOTCONN}, + // WSAESHUTDOWN + {WsaError.WSAESHUTDOWN, LinuxError.ESHUTDOWN}, + // WSAETOOMANYREFS + {WsaError.WSAETOOMANYREFS, LinuxError.ETOOMANYREFS}, + // WSAETIMEDOUT + {WsaError.WSAETIMEDOUT, LinuxError.ETIMEDOUT}, + // WSAECONNREFUSED + {WsaError.WSAECONNREFUSED, LinuxError.ECONNREFUSED}, + // WSAELOOP + {WsaError.WSAELOOP, LinuxError.ELOOP}, + // WSAENAMETOOLONG + {WsaError.WSAENAMETOOLONG, LinuxError.ENAMETOOLONG}, + // WSAEHOSTDOWN + {WsaError.WSAEHOSTDOWN, LinuxError.EHOSTDOWN}, + // WSAEHOSTUNREACH + {WsaError.WSAEHOSTUNREACH, LinuxError.EHOSTUNREACH}, + // WSAENOTEMPTY + {WsaError.WSAENOTEMPTY, LinuxError.ENOTEMPTY}, + // WSAEUSERS + {WsaError.WSAEUSERS, LinuxError.EUSERS}, + // WSAEDQUOT + {WsaError.WSAEDQUOT, LinuxError.EDQUOT}, + // WSAESTALE + {WsaError.WSAESTALE, LinuxError.ESTALE}, + // WSAEREMOTE + {WsaError.WSAEREMOTE, LinuxError.EREMOTE}, + // WSAEINVAL + {WsaError.WSAEINVAL, LinuxError.EINVAL}, + // WSAEFAULT + {WsaError.WSAEFAULT, LinuxError.EFAULT}, + // NOERROR + {0, 0} + }; + + private bool _isPrivileged; + + private List _sockets = new List(); + + public IClient(ServiceCtx context, bool isPrivileged) + { + _isPrivileged = isPrivileged; + } + + private LinuxError ConvertError(WsaError errorCode) + { + if (!_errorMap.TryGetValue(errorCode, out LinuxError errno)) + { + errno = (LinuxError)errorCode; + } + + return errno; + } + + private ResultCode WriteWinSock2Error(ServiceCtx context, WsaError errorCode) + { + return WriteBsdResult(context, -1, ConvertError(errorCode)); + } + + private ResultCode WriteBsdResult(ServiceCtx context, int result, LinuxError errorCode = 0) + { + if (errorCode != LinuxError.SUCCESS) + { + result = -1; + } + + context.ResponseData.Write(result); + context.ResponseData.Write((int)errorCode); + + return ResultCode.Success; + } + + private BsdSocket RetrieveSocket(int socketFd) + { + if (socketFd >= 0 && _sockets.Count > socketFd) + { + return _sockets[socketFd]; + } + + return null; + } + + private LinuxError SetResultErrno(Socket socket, int result) + { + return result == 0 && !socket.Blocking ? LinuxError.EWOULDBLOCK : LinuxError.SUCCESS; + } + + private AddressFamily ConvertFromBsd(int domain) + { + if (domain == 2) + { + return AddressFamily.InterNetwork; + } + + // FIXME: AF_ROUTE ignored, is that really needed? + return AddressFamily.Unknown; + } + + private ResultCode SocketInternal(ServiceCtx context, bool exempt) + { + AddressFamily domain = (AddressFamily)context.RequestData.ReadInt32(); + SocketType type = (SocketType)context.RequestData.ReadInt32(); + ProtocolType protocol = (ProtocolType)context.RequestData.ReadInt32(); + + if (domain == AddressFamily.Unknown) + { + return WriteBsdResult(context, -1, LinuxError.EPROTONOSUPPORT); + } + else if ((type == SocketType.Seqpacket || type == SocketType.Raw) && !_isPrivileged) + { + if (domain != AddressFamily.InterNetwork || type != SocketType.Raw || protocol != ProtocolType.Icmp) + { + return WriteBsdResult(context, -1, LinuxError.ENOENT); + } + } + + BsdSocket newBsdSocket = new BsdSocket + { + Family = (int)domain, + Type = (int)type, + Protocol = (int)protocol, + Handle = new Socket(domain, type, protocol) + }; + + _sockets.Add(newBsdSocket); + + if (exempt) + { + newBsdSocket.Handle.Disconnect(true); + } + + return WriteBsdResult(context, _sockets.Count - 1); + } + + private IPEndPoint ParseSockAddr(ServiceCtx context, long bufferPosition, long bufferSize) + { + int size = context.Memory.ReadByte(bufferPosition); + int family = context.Memory.ReadByte(bufferPosition + 1); + int port = EndianSwap.Swap16(context.Memory.ReadUInt16(bufferPosition + 2)); + + byte[] rawIp = context.Memory.ReadBytes(bufferPosition + 4, 4); + + return new IPEndPoint(new IPAddress(rawIp), port); + } + + private void WriteSockAddr(ServiceCtx context, long bufferPosition, IPEndPoint endPoint) + { + context.Memory.WriteByte(bufferPosition, 0); + context.Memory.WriteByte(bufferPosition + 1, (byte)endPoint.AddressFamily); + context.Memory.WriteUInt16(bufferPosition + 2, EndianSwap.Swap16((ushort)endPoint.Port)); + context.Memory.WriteBytes(bufferPosition + 4, endPoint.Address.GetAddressBytes()); + } + + private void WriteSockAddr(ServiceCtx context, long bufferPosition, BsdSocket socket, bool isRemote) + { + IPEndPoint endPoint = (isRemote ? socket.Handle.RemoteEndPoint : socket.Handle.LocalEndPoint) as IPEndPoint; + + WriteSockAddr(context, bufferPosition, endPoint); + } + + [Command(0)] + // Initialize(nn::socket::BsdBufferConfig config, u64 pid, u64 transferMemorySize, KObject, pid) -> u32 bsd_errno + public ResultCode RegisterClient(ServiceCtx context) + { + /* + typedef struct { + u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0. + u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed). + u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed). + u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value. + u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value. + u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes). + u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes). + u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8). + } BsdBufferConfig; + */ + + // bsd_error + context.ResponseData.Write(0); + + Logger.PrintStub(LogClass.ServiceBsd); + + return ResultCode.Success; + } + + [Command(1)] + // StartMonitoring(u64, pid) + public ResultCode StartMonitoring(ServiceCtx context) + { + ulong unknown0 = context.RequestData.ReadUInt64(); + + Logger.PrintStub(LogClass.ServiceBsd, new { unknown0 }); + + return ResultCode.Success; + } + + [Command(2)] + // Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) + public ResultCode Socket(ServiceCtx context) + { + return SocketInternal(context, false); + } + + [Command(3)] + // SocketExempt(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) + public ResultCode SocketExempt(ServiceCtx context) + { + return SocketInternal(context, true); + } + + [Command(4)] + // Open(u32 flags, array path) -> (i32 ret, u32 bsd_errno) + public ResultCode Open(ServiceCtx context) + { + (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(); + + int flags = context.RequestData.ReadInt32(); + + byte[] rawPath = context.Memory.ReadBytes(bufferPosition, bufferSize); + string path = Encoding.ASCII.GetString(rawPath); + + WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + + Logger.PrintStub(LogClass.ServiceBsd, new { path, flags }); + + return ResultCode.Success; + } + + [Command(5)] + // Select(u32 nfds, nn::socket::timeout timeout, buffer readfds_in, buffer writefds_in, buffer errorfds_in) -> (i32 ret, u32 bsd_errno, buffer readfds_out, buffer writefds_out, buffer errorfds_out) + public ResultCode Select(ServiceCtx context) + { + WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + + Logger.PrintStub(LogClass.ServiceBsd); + + return ResultCode.Success; + } + + [Command(6)] + // Poll(u32 nfds, u32 timeout, buffer fds) -> (i32 ret, u32 bsd_errno, buffer) + public ResultCode Poll(ServiceCtx context) + { + int fdsCount = context.RequestData.ReadInt32(); + int timeout = context.RequestData.ReadInt32(); + + (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(); + + + if (timeout < -1 || fdsCount < 0 || (fdsCount * 8) > bufferSize) + { + return WriteBsdResult(context, -1, LinuxError.EINVAL); + } + + PollEvent[] events = new PollEvent[fdsCount]; + + for (int i = 0; i < fdsCount; i++) + { + int socketFd = context.Memory.ReadInt32(bufferPosition + i * 8); + + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket == null) + { + return WriteBsdResult(context, -1, LinuxError.EBADF);} + + PollEvent.EventTypeMask inputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 4); + PollEvent.EventTypeMask outputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 6); + + events[i] = new PollEvent(socketFd, socket, inputEvents, outputEvents); + } + + List readEvents = new List(); + List writeEvents = new List(); + List errorEvents = new List(); + + foreach (PollEvent Event in events) + { + bool isValidEvent = false; + + if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) + { + readEvents.Add(Event.Socket.Handle); + errorEvents.Add(Event.Socket.Handle); + + isValidEvent = true; + } + + if ((Event.InputEvents & PollEvent.EventTypeMask.UrgentInput) != 0) + { + readEvents.Add(Event.Socket.Handle); + errorEvents.Add(Event.Socket.Handle); + + isValidEvent = true; + } + + if ((Event.InputEvents & PollEvent.EventTypeMask.Output) != 0) + { + writeEvents.Add(Event.Socket.Handle); + errorEvents.Add(Event.Socket.Handle); + + isValidEvent = true; + } + + if ((Event.InputEvents & PollEvent.EventTypeMask.Error) != 0) + { + errorEvents.Add(Event.Socket.Handle); + isValidEvent = true; + } + + if (!isValidEvent) + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Poll input event type: {Event.InputEvents}"); + return WriteBsdResult(context, -1, LinuxError.EINVAL); + } + } + + try + { + System.Net.Sockets.Socket.Select(readEvents, writeEvents, errorEvents, timeout); + } + catch (SocketException exception) + { + return WriteWinSock2Error(context, (WsaError)exception.ErrorCode); + } + + for (int i = 0; i < fdsCount; i++) + { + PollEvent Event = events[i]; + context.Memory.WriteInt32(bufferPosition + i * 8, Event.SocketFd); + context.Memory.WriteInt16(bufferPosition + i * 8 + 4, (short)Event.InputEvents); + + PollEvent.EventTypeMask outputEvents = 0; + + Socket socket = Event.Socket.Handle; + + if (errorEvents.Contains(socket)) + { + outputEvents |= PollEvent.EventTypeMask.Error; + + if (!socket.Connected || !socket.IsBound) + { + outputEvents |= PollEvent.EventTypeMask.Disconnected; + } + } + + if (readEvents.Contains(socket)) + { + if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) + { + outputEvents |= PollEvent.EventTypeMask.Input; + } + } + + if (writeEvents.Contains(socket)) + { + outputEvents |= PollEvent.EventTypeMask.Output; + } + + context.Memory.WriteInt16(bufferPosition + i * 8 + 6, (short)outputEvents); + } + + return WriteBsdResult(context, readEvents.Count + writeEvents.Count + errorEvents.Count, LinuxError.SUCCESS); + } + + [Command(7)] + // Sysctl(buffer, buffer) -> (i32 ret, u32 bsd_errno, u32, buffer) + public ResultCode Sysctl(ServiceCtx context) + { + WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + + Logger.PrintStub(LogClass.ServiceBsd); + + return ResultCode.Success; + } + + [Command(8)] + // Recv(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, array message) + public ResultCode Recv(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); + + (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0 + && (socketFlags & SocketFlags.Peek) == 0) + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}"); + return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + } + + byte[] receivedBuffer = new byte[receiveLength]; + + try + { + result = socket.Handle.Receive(receivedBuffer, socketFlags); + errno = SetResultErrno(socket.Handle, result); + + context.Memory.WriteBytes(receivePosition, receivedBuffer); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, result, errno); + } + + [Command(9)] + // RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer message, buffer) + public ResultCode RecvFrom(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); + + (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); + (long sockAddrOutPosition, long sockAddrOutSize) = context.Request.GetBufferType0x22(1); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0 + && (socketFlags & SocketFlags.Peek) == 0) + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}"); + + return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + } + + byte[] receivedBuffer = new byte[receiveLength]; + EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0); + + try + { + result = socket.Handle.ReceiveFrom(receivedBuffer, receivedBuffer.Length, socketFlags, ref endPoint); + errno = SetResultErrno(socket.Handle, result); + + context.Memory.WriteBytes(receivePosition, receivedBuffer); + WriteSockAddr(context, sockAddrOutPosition, (IPEndPoint)endPoint); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, result, errno); + } + + [Command(10)] + // Send(u32 socket, u32 flags, buffer) -> (i32 ret, u32 bsd_errno) + public ResultCode Send(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); + + (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand + && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute) + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}"); + + return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + } + + byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); + + try + { + result = socket.Handle.Send(sendBuffer, socketFlags); + errno = SetResultErrno(socket.Handle, result); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + + } + + return WriteBsdResult(context, result, errno); + } + + [Command(11)] + // SendTo(u32 socket, u32 flags, buffer, buffer) -> (i32 ret, u32 bsd_errno) + public ResultCode SendTo(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32(); + + (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); + (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(1); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand + && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute) + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}"); + + return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + } + + byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); + EndPoint endPoint = ParseSockAddr(context, bufferPosition, bufferSize); + + try + { + result = socket.Handle.SendTo(sendBuffer, sendBuffer.Length, socketFlags, endPoint); + errno = SetResultErrno(socket.Handle, result); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + + } + + return WriteBsdResult(context, result, errno); + } + + [Command(12)] + // Accept(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) + public ResultCode Accept(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + Socket newSocket = null; + + try + { + newSocket = socket.Handle.Accept(); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + + if (newSocket == null && errno == LinuxError.SUCCESS) + { + errno = LinuxError.EWOULDBLOCK; + } + else if (errno == LinuxError.SUCCESS) + { + BsdSocket newBsdSocket = new BsdSocket + { + Family = (int)newSocket.AddressFamily, + Type = (int)newSocket.SocketType, + Protocol = (int)newSocket.ProtocolType, + Handle = newSocket + }; + + _sockets.Add(newBsdSocket); + + WriteSockAddr(context, bufferPos, newBsdSocket, true); + + WriteBsdResult(context, _sockets.Count - 1, errno); + + context.ResponseData.Write(0x10); + + return ResultCode.Success; + } + } + + return WriteBsdResult(context, -1, errno); + } + + [Command(13)] + // Bind(u32 socket, buffer addr) -> (i32 ret, u32 bsd_errno) + public ResultCode Bind(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + try + { + IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize); + + socket.Handle.Bind(endPoint); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(14)] + // Connect(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) + public ResultCode Connect(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + try + { + IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize); + + socket.Handle.Connect(endPoint); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(15)] + // GetPeerName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) + public ResultCode GetPeerName(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + WriteSockAddr(context, bufferPos, socket, true); + WriteBsdResult(context, 0, errno); + context.ResponseData.Write(0x10); + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(16)] + // GetSockName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) + public ResultCode GetSockName(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + WriteSockAddr(context, bufferPos, socket, false); + WriteBsdResult(context, 0, errno); + context.ResponseData.Write(0x10); + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(17)] + // GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer) + public ResultCode GetSockOpt(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + int level = context.RequestData.ReadInt32(); + int optionName = context.RequestData.ReadInt32(); + + (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.ENOPROTOOPT; + + if (level == 0xFFFF) + { + errno = HandleGetSocketOption(context, socket, (SocketOptionName)optionName, bufferPosition, bufferSize); + } + else + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported GetSockOpt Level: {(SocketOptionLevel)level}"); + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(18)] + // Listen(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno) + public ResultCode Listen(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + int backlog = context.RequestData.ReadInt32(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + try + { + socket.Handle.Listen(backlog); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(19)] + // Ioctl(u32 fd, u32 request, u32 bufcount, buffer, buffer, buffer, buffer) -> (i32 ret, u32 bsd_errno, buffer, buffer, buffer, buffer) + public ResultCode Ioctl(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + BsdIoctl cmd = (BsdIoctl)context.RequestData.ReadInt32(); + int bufferCount = context.RequestData.ReadInt32(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + switch (cmd) + { + case BsdIoctl.AtMark: + errno = LinuxError.SUCCESS; + + (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22(); + + // FIXME: OOB not implemented. + context.Memory.WriteInt32(bufferPosition, 0); + break; + + default: + errno = LinuxError.EOPNOTSUPP; + + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Ioctl Cmd: {cmd}"); + break; + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(20)] + // Fcntl(u32 socket, u32 cmd, u32 arg) -> (i32 ret, u32 bsd_errno) + public ResultCode Fcntl(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + int cmd = context.RequestData.ReadInt32(); + int arg = context.RequestData.ReadInt32(); + + int result = 0; + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.SUCCESS; + + if (cmd == 0x3) + { + result = !socket.Handle.Blocking ? 0x800 : 0; + } + else if (cmd == 0x4 && arg == 0x800) + { + socket.Handle.Blocking = false; + result = 0; + } + else + { + errno = LinuxError.EOPNOTSUPP; + } + } + + return WriteBsdResult(context, result, errno); + } + + private LinuxError HandleGetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize) + { + try + { + byte[] optionValue = new byte[optionValueSize]; + + switch (optionName) + { + case SocketOptionName.Broadcast: + case SocketOptionName.DontLinger: + case SocketOptionName.Debug: + case SocketOptionName.Error: + case SocketOptionName.KeepAlive: + case SocketOptionName.OutOfBandInline: + case SocketOptionName.ReceiveBuffer: + case SocketOptionName.ReceiveTimeout: + case SocketOptionName.SendBuffer: + case SocketOptionName.SendTimeout: + case SocketOptionName.Type: + case SocketOptionName.Linger: + socket.Handle.GetSocketOption(SocketOptionLevel.Socket, optionName, optionValue); + context.Memory.WriteBytes(optionValuePosition, optionValue); + + return LinuxError.SUCCESS; + + case (SocketOptionName)0x200: + socket.Handle.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue); + context.Memory.WriteBytes(optionValuePosition, optionValue); + + return LinuxError.SUCCESS; + + default: + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}"); + + return LinuxError.EOPNOTSUPP; + } + } + catch (SocketException exception) + { + return ConvertError((WsaError)exception.ErrorCode); + } + } + + private LinuxError HandleSetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize) + { + try + { + switch (optionName) + { + case SocketOptionName.Broadcast: + case SocketOptionName.DontLinger: + case SocketOptionName.Debug: + case SocketOptionName.Error: + case SocketOptionName.KeepAlive: + case SocketOptionName.OutOfBandInline: + case SocketOptionName.ReceiveBuffer: + case SocketOptionName.ReceiveTimeout: + case SocketOptionName.SendBuffer: + case SocketOptionName.SendTimeout: + case SocketOptionName.Type: + case SocketOptionName.ReuseAddress: + socket.Handle.SetSocketOption(SocketOptionLevel.Socket, optionName, context.Memory.ReadInt32(optionValuePosition)); + + return LinuxError.SUCCESS; + + case (SocketOptionName)0x200: + socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, context.Memory.ReadInt32(optionValuePosition)); + + return LinuxError.SUCCESS; + + case SocketOptionName.Linger: + socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, + new LingerOption(context.Memory.ReadInt32(optionValuePosition) != 0, context.Memory.ReadInt32(optionValuePosition + 4))); + + return LinuxError.SUCCESS; + + default: + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}"); + + return LinuxError.EOPNOTSUPP; + } + } + catch (SocketException exception) + { + return ConvertError((WsaError)exception.ErrorCode); + } + } + + [Command(21)] + // SetSockOpt(u32 socket, u32 level, u32 option_name, buffer option_value) -> (i32 ret, u32 bsd_errno) + public ResultCode SetSockOpt(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + int level = context.RequestData.ReadInt32(); + int optionName = context.RequestData.ReadInt32(); + + (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.ENOPROTOOPT; + + if (level == 0xFFFF) + { + errno = HandleSetSocketOption(context, socket, (SocketOptionName)optionName, bufferPos, bufferSize); + } + else + { + Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported SetSockOpt Level: {(SocketOptionLevel)level}"); + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(22)] + // Shutdown(u32 socket, u32 how) -> (i32 ret, u32 bsd_errno) + public ResultCode Shutdown(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + int how = context.RequestData.ReadInt32(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + errno = LinuxError.EINVAL; + + if (how >= 0 && how <= 2) + { + errno = LinuxError.SUCCESS; + + try + { + socket.Handle.Shutdown((SocketShutdown)how); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(23)] + // ShutdownAllSockets(u32 how) -> (i32 ret, u32 bsd_errno) + public ResultCode ShutdownAllSockets(ServiceCtx context) + { + int how = context.RequestData.ReadInt32(); + + LinuxError errno = LinuxError.EINVAL; + + if (how >= 0 && how <= 2) + { + errno = LinuxError.SUCCESS; + + foreach (BsdSocket socket in _sockets) + { + if (socket != null) + { + try + { + socket.Handle.Shutdown((SocketShutdown)how); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + break; + } + } + } + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(24)] + // Write(u32 socket, buffer message) -> (i32 ret, u32 bsd_errno) + public ResultCode Write(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + byte[] sendBuffer = context.Memory.ReadBytes(sendPosition, sendSize); + + try + { + result = socket.Handle.Send(sendBuffer); + errno = SetResultErrno(socket.Handle, result); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, result, errno); + } + + [Command(25)] + // Read(u32 socket) -> (i32 ret, u32 bsd_errno, buffer message) + public ResultCode Read(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + int result = -1; + + if (socket != null) + { + byte[] receivedBuffer = new byte[receiveLength]; + + try + { + result = socket.Handle.Receive(receivedBuffer); + errno = SetResultErrno(socket.Handle, result); + } + catch (SocketException exception) + { + errno = ConvertError((WsaError)exception.ErrorCode); + } + } + + return WriteBsdResult(context, result, errno); + } + + [Command(26)] + // Close(u32 socket) -> (i32 ret, u32 bsd_errno) + public ResultCode Close(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + + LinuxError errno = LinuxError.EBADF; + BsdSocket socket = RetrieveSocket(socketFd); + + if (socket != null) + { + socket.Handle.Close(); + + _sockets[socketFd] = null; + + errno = LinuxError.SUCCESS; + } + + return WriteBsdResult(context, 0, errno); + } + + [Command(27)] + // DuplicateSocket(u32 socket, u64 reserved) -> (i32 ret, u32 bsd_errno) + public ResultCode DuplicateSocket(ServiceCtx context) + { + int socketFd = context.RequestData.ReadInt32(); + ulong reserved = context.RequestData.ReadUInt64(); + + LinuxError errno = LinuxError.ENOENT; + int newSockFd = -1; + + if (_isPrivileged) + { + errno = LinuxError.EBADF; + + BsdSocket oldSocket = RetrieveSocket(socketFd); + + if (oldSocket != null) + { + _sockets.Add(oldSocket); + newSockFd = _sockets.Count - 1; + } + } + + return WriteBsdResult(context, newSockFd, errno); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ServerInterface.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ServerInterface.cs new file mode 100644 index 00000000..798fc015 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ServerInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +{ + [Service("bsdcfg")] + class ServerInterface : IpcService + { + public ServerInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs new file mode 100644 index 00000000..421a255c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +{ + enum BsdIoctl + { + AtMark = 0x40047307 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocket.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocket.cs new file mode 100644 index 00000000..2d5bf429 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocket.cs @@ -0,0 +1,13 @@ +using System.Net.Sockets; + +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +{ + class BsdSocket + { + public int Family; + public int Type; + public int Protocol; + + public Socket Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs new file mode 100644 index 00000000..ff47a4c7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs @@ -0,0 +1,28 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +{ + class PollEvent + { + public enum EventTypeMask + { + Input = 1, + UrgentInput = 2, + Output = 4, + Error = 8, + Disconnected = 0x10, + Invalid = 0x20 + } + + public int SocketFd { get; private set; } + public BsdSocket Socket { get; private set; } + public EventTypeMask InputEvents { get; private set; } + public EventTypeMask OutputEvents { get; private set; } + + public PollEvent(int socketFd, BsdSocket socket, EventTypeMask inputEvents, EventTypeMask outputEvents) + { + SocketFd = socketFd; + Socket = socket; + InputEvents = inputEvents; + OutputEvents = outputEvents; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterface.cs b/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterface.cs new file mode 100644 index 00000000..f5877697 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Ethc +{ + [Service("ethc:c")] + class IEthInterface : IpcService + { + public IEthInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterfaceGroup.cs b/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterfaceGroup.cs new file mode 100644 index 00000000..9832e448 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Ethc/IEthInterfaceGroup.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Ethc +{ + [Service("ethc:i")] + class IEthInterfaceGroup : IpcService + { + public IEthInterfaceGroup(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs new file mode 100644 index 00000000..277bc374 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs @@ -0,0 +1,268 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Services.Settings; +using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd +{ + [Service("nsd:a")] // Max sessions: 5 + [Service("nsd:u")] // Max sessions: 20 + class IManager : IpcService + { + private NsdSettings _nsdSettings; + private FqdnResolver _fqdnResolver; + + private bool _isInitialized = false; + + public IManager(ServiceCtx context) + { + // TODO: Load nsd settings through the savedata 0x80000000000000B0 (nsdsave:/). + + NxSettings.Settings.TryGetValue("nsd!test_mode", out object testMode); + + _nsdSettings = new NsdSettings + { + Initialized = true, + TestMode = (bool)testMode + }; + + _fqdnResolver = new FqdnResolver(_nsdSettings); + + _isInitialized = true; + } + + [Command(10)] + // GetSettingName() -> buffer, 0x16> + public ResultCode GetSettingName(ServiceCtx context) + { + (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); + + ResultCode result = _fqdnResolver.GetSettingName(context, out string settingName); + + if (result == ResultCode.Success) + { + byte[] settingNameBuffer = Encoding.UTF8.GetBytes(settingName + '\0'); + + context.Memory.WriteBytes(outputPosition, settingNameBuffer); + } + + return result; + } + + [Command(11)] + // GetEnvironmentIdentifier() -> buffer, 0x16> + public ResultCode GetEnvironmentIdentifier(ServiceCtx context) + { + (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); + + ResultCode result = _fqdnResolver.GetEnvironmentIdentifier(context, out string identifier); + + if (result == ResultCode.Success) + { + byte[] identifierBuffer = Encoding.UTF8.GetBytes(identifier + '\0'); + + context.Memory.WriteBytes(outputPosition, identifierBuffer); + } + + return result; + } + + [Command(12)] + // GetDeviceId() -> bytes<0x10, 1> + public ResultCode GetDeviceId(ServiceCtx context) + { + // NOTE: Stubbed in system module. + + return ResultCode.Success; + } + + [Command(13)] + // DeleteSettings(u32) + public ResultCode DeleteSettings(ServiceCtx context) + { + uint unknown = context.RequestData.ReadUInt32(); + + if (!_isInitialized) + { + return ResultCode.ServiceNotInitialized; + } + + if (unknown > 1) + { + return ResultCode.InvalidArgument; + } + + if (unknown == 1) + { + NxSettings.Settings.TryGetValue("nsd!environment_identifier", out object environmentIdentifier); + + if ((string)environmentIdentifier == _nsdSettings.Environment) + { + // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode. + } + else + { + // TODO: Mount the savedata file and return ResultCode. + } + } + else + { + // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode. + } + + return ResultCode.Success; + } + + [Command(14)] + // ImportSettings(u32, buffer) -> buffer + public ResultCode ImportSettings(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(15)] + // Unknown(bytes<1>) + public ResultCode Unknown(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(20)] + // Resolve(buffer, 0x15>) -> buffer, 0x16> + public ResultCode Resolve(ServiceCtx context) + { + (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); + + ResultCode result = _fqdnResolver.ResolveEx(context, out ResultCode errorCode, out string resolvedAddress); + + byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress + '\0'); + + context.Memory.WriteBytes(outputPosition, resolvedAddressBuffer); + + return result; + } + + [Command(21)] + // ResolveEx(buffer, 0x15>) -> (u32, buffer, 0x16>) + public ResultCode ResolveEx(ServiceCtx context) + { + (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(); + + ResultCode result = _fqdnResolver.ResolveEx(context, out ResultCode errorCode, out string resolvedAddress); + + byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress + '\0'); + + context.Memory.WriteBytes(outputPosition, resolvedAddressBuffer); + + context.ResponseData.Write((int)errorCode); + + return result; + } + + [Command(30)] + // GetNasServiceSetting(buffer, 0x15>) -> buffer, 0x16> + public ResultCode GetNasServiceSetting(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(31)] + // GetNasServiceSettingEx(buffer, 0x15>) -> (u32, buffer, 0x16>) + public ResultCode GetNasServiceSettingEx(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(40)] + // GetNasRequestFqdn() -> buffer, 0x16> + public ResultCode GetNasRequestFqdn(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(41)] + // GetNasRequestFqdnEx() -> (u32, buffer, 0x16>) + public ResultCode GetNasRequestFqdnEx(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(42)] + // GetNasApiFqdn() -> buffer, 0x16> + public ResultCode GetNasApiFqdn(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(43)] + // GetNasApiFqdnEx() -> (u32, buffer, 0x16>) + public ResultCode GetNasApiFqdnEx(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(50)] + // GetCurrentSetting() -> buffer, 0x16> + public ResultCode GetCurrentSetting(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(60)] + // ReadSaveDataFromFsForTest() -> buffer, 0x16> + public ResultCode ReadSaveDataFromFsForTest(ServiceCtx context) + { + if (!_isInitialized) + { + return ResultCode.ServiceNotInitialized; + } + + // TODO: Call nn::nsd::detail::fs::ReadSaveDataWithOffset() at offset 0 to write the + // whole savedata inside the buffer. + + Logger.PrintStub(LogClass.ServiceNsd); + + return ResultCode.Success; + } + + [Command(61)] + // WriteSaveDataToFsForTest(buffer, 0x15>) + public ResultCode WriteSaveDataToFsForTest(ServiceCtx context) + { + // NOTE: Stubbed in system module. + + if (_isInitialized) + { + return ResultCode.NotImplemented; + } + else + { + return ResultCode.ServiceNotInitialized; + } + } + + [Command(62)] + // DeleteSaveDataOfFsForTest() + public ResultCode DeleteSaveDataOfFsForTest(ServiceCtx context) + { + // NOTE: Stubbed in system module. + + if (_isInitialized) + { + return ResultCode.NotImplemented; + } + else + { + return ResultCode.ServiceNotInitialized; + } + } + + [Command(63)] + // IsChangeEnvironmentIdentifierDisabled() -> bytes<1> + public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs new file mode 100644 index 00000000..aaab7b3b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs @@ -0,0 +1,131 @@ +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager +{ + class FqdnResolver + { + private const string _dummyAddress = "unknown.dummy.nintendo.net"; + + private NsdSettings _nsdSettings; + + public FqdnResolver(NsdSettings nsdSettings) + { + _nsdSettings = nsdSettings; + } + + public ResultCode GetSettingName(ServiceCtx context, out string settingName) + { + if (_nsdSettings.TestMode) + { + settingName = ""; + + return ResultCode.NotImplemented; + } + else + { + settingName = ""; + + if (true) // TODO: Determine field (struct + 0x2C) + { + settingName = _nsdSettings.Environment; + + return ResultCode.Success; + } + + return ResultCode.NullOutputObject; + } + } + + public ResultCode GetEnvironmentIdentifier(ServiceCtx context, out string identifier) + { + if (_nsdSettings.TestMode) + { + identifier = "rre"; + + return ResultCode.NotImplemented; + } + else + { + identifier = _nsdSettings.Environment; + } + + return ResultCode.Success; + } + + public ResultCode Resolve(ServiceCtx context, string address, out string resolvedAddress) + { + if (address != "api.sect.srv.nintendo.net" || address != "conntest.nintendowifi.net") + { + // TODO: Load Environment from the savedata. + address = address.Replace("%", _nsdSettings.Environment); + + resolvedAddress = ""; + + if (_nsdSettings == null) + { + return ResultCode.SettingsNotInitialized; + } + + if (!_nsdSettings.Initialized) + { + return ResultCode.SettingsNotLoaded; + } + + switch (address) + { + case "e97b8a9d672e4ce4845ec6947cd66ef6-sb-api.accounts.nintendo.com": // dp1 environment + resolvedAddress = "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com"; + break; + case "api.accounts.nintendo.com": // dp1 environment + resolvedAddress = "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com"; + break; + case "e97b8a9d672e4ce4845ec6947cd66ef6-sb.accounts.nintendo.com": // lp1 environment + resolvedAddress = "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com"; + break; + case "accounts.nintendo.com": // lp1 environment + resolvedAddress = "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com"; + break; + /* + // TODO: Determine fields of the struct. + case "": // + 0xEB8 || + 0x2BE8 + resolvedAddress = ""; // + 0xEB8 + 0x300 || + 0x2BE8 + 0x300 + break; + */ + default: + resolvedAddress = address; + break; + } + } + else + { + resolvedAddress = address; + } + + return ResultCode.Success; + } + + public ResultCode ResolveEx(ServiceCtx context, out ResultCode resultCode, out string resolvedAddress) + { + (long inputPosition, long inputSize) = context.Request.GetBufferType0x21(); + + byte[] addressBuffer = context.Memory.ReadBytes(inputPosition, inputSize); + string address = Encoding.UTF8.GetString(addressBuffer); + + resultCode = Resolve(context, address, out resolvedAddress); + + if (resultCode != ResultCode.Success) + { + resolvedAddress = _dummyAddress; + } + + if (_nsdSettings.TestMode) + { + return ResultCode.Success; + } + else + { + return resultCode; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs new file mode 100644 index 00000000..0e636f9a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd +{ + enum ResultCode + { + ModuleId = 141, + ErrorCodeShift = 9, + + Success = 0, + + NotImplemented = ( 1 << ErrorCodeShift) | ModuleId, + InvalidObject1 = ( 3 << ErrorCodeShift) | ModuleId, + InvalidObject2 = ( 4 << ErrorCodeShift) | ModuleId, + NullOutputObject = ( 5 << ErrorCodeShift) | ModuleId, + SettingsNotLoaded = ( 6 << ErrorCodeShift) | ModuleId, + InvalidArgument = ( 8 << ErrorCodeShift) | ModuleId, + SettingsNotInitialized = ( 10 << ErrorCodeShift) | ModuleId, + ServiceNotInitialized = (400 << ErrorCodeShift) | ModuleId, + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs new file mode 100644 index 00000000..2b31cb1d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd +{ + class NsdSettings + { + public bool Initialized; + public bool TestMode; + public string Environment = "lp1"; // or "dd1" if devkit. + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs new file mode 100644 index 00000000..1cf2aa1c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs @@ -0,0 +1,387 @@ +using Ryujinx.Common.Logging; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres +{ + [Service("sfdnsres")] + class IResolver : IpcService + { + public IResolver(ServiceCtx context) { } + + private long SerializeHostEnt(ServiceCtx context, IPHostEntry hostEntry, List addresses = null) + { + long originalBufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferPosition = originalBufferPosition; + long bufferSize = context.Request.ReceiveBuff[0].Size; + + string hostName = hostEntry.HostName + '\0'; + + // h_name + context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(hostName)); + bufferPosition += hostName.Length; + + // h_aliases list size + context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(hostEntry.Aliases.Length)); + bufferPosition += 4; + + // Actual aliases + foreach (string alias in hostEntry.Aliases) + { + context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(alias + '\0')); + bufferPosition += alias.Length + 1; + } + + // h_addrtype but it's a short (also only support IPv4) + context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)2)); + bufferPosition += 2; + + // h_length but it's a short + context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)4)); + bufferPosition += 2; + + // Ip address count, we can only support ipv4 (blame Nintendo) + context.Memory.WriteInt32(bufferPosition, addresses != null ? IPAddress.HostToNetworkOrder(addresses.Count) : 0); + bufferPosition += 4; + + if (addresses != null) + { + foreach (IPAddress ip in addresses) + { + context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(BitConverter.ToInt32(ip.GetAddressBytes(), 0))); + bufferPosition += 4; + } + } + + return bufferPosition - originalBufferPosition; + } + + private string GetGaiStringErrorFromErrorCode(GaiError errorCode) + { + if (errorCode > GaiError.Max) + { + errorCode = GaiError.Max; + } + + switch (errorCode) + { + case GaiError.AddressFamily: + return "Address family for hostname not supported"; + case GaiError.Again: + return "Temporary failure in name resolution"; + case GaiError.BadFlags: + return "Invalid value for ai_flags"; + case GaiError.Fail: + return "Non-recoverable failure in name resolution"; + case GaiError.Family: + return "ai_family not supported"; + case GaiError.Memory: + return "Memory allocation failure"; + case GaiError.NoData: + return "No address associated with hostname"; + case GaiError.NoName: + return "hostname nor servname provided, or not known"; + case GaiError.Service: + return "servname not supported for ai_socktype"; + case GaiError.SocketType: + return "ai_socktype not supported"; + case GaiError.System: + return "System error returned in errno"; + case GaiError.BadHints: + return "Invalid value for hints"; + case GaiError.Protocol: + return "Resolved protocol is unknown"; + case GaiError.Overflow: + return "Argument buffer overflow"; + case GaiError.Max: + return "Unknown error"; + default: + return "Success"; + } + } + + private string GetHostStringErrorFromErrorCode(NetDbError errorCode) + { + if (errorCode <= NetDbError.Internal) + { + return "Resolver internal error"; + } + + switch (errorCode) + { + case NetDbError.Success: + return "Resolver Error 0 (no error)"; + case NetDbError.HostNotFound: + return "Unknown host"; + case NetDbError.TryAgain: + return "Host name lookup failure"; + case NetDbError.NoRecovery: + return "Unknown server error"; + case NetDbError.NoData: + return "No address associated with name"; + default: + return "Unknown resolver error"; + } + } + + private List GetIpv4Addresses(IPHostEntry hostEntry) + { + List result = new List(); + foreach (IPAddress ip in hostEntry.AddressList) + { + if (ip.AddressFamily == AddressFamily.InterNetwork) + result.Add(ip); + } + return result; + } + + [Command(0)] + // SetDnsAddressesPrivate(u32, buffer) + public ResultCode SetDnsAddressesPrivate(ServiceCtx context) + { + uint unknown0 = context.RequestData.ReadUInt32(); + long bufferPosition = context.Request.SendBuff[0].Position; + long bufferSize = context.Request.SendBuff[0].Size; + + // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness. + Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); + + return ResultCode.NotAllocated; + } + + [Command(1)] + // GetDnsAddressPrivate(u32) -> buffer + public ResultCode GetDnsAddressesPrivate(ServiceCtx context) + { + uint unknown0 = context.RequestData.ReadUInt32(); + + // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness. + Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); + + return ResultCode.NotAllocated; + } + + [Command(2)] + // GetHostByName(u8, u32, u64, pid, buffer) -> (u32, u32, u32, buffer) + public ResultCode GetHostByName(ServiceCtx context) + { + byte[] rawName = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size); + string name = Encoding.ASCII.GetString(rawName).TrimEnd('\0'); + + // TODO: use params + bool enableNsdResolve = context.RequestData.ReadInt32() == 1; + int timeOut = context.RequestData.ReadInt32(); + ulong pidPlaceholder = context.RequestData.ReadUInt64(); + + IPHostEntry hostEntry = null; + + NetDbError netDbErrorCode = NetDbError.Success; + GaiError errno = GaiError.Overflow; + long serializedSize = 0; + + if (name.Length <= 255) + { + try + { + hostEntry = Dns.GetHostEntry(name); + } + catch (SocketException exception) + { + netDbErrorCode = NetDbError.Internal; + + if (exception.ErrorCode == 11001) + { + netDbErrorCode = NetDbError.HostNotFound; + errno = GaiError.NoData; + } + else if (exception.ErrorCode == 11002) + { + netDbErrorCode = NetDbError.TryAgain; + } + else if (exception.ErrorCode == 11003) + { + netDbErrorCode = NetDbError.NoRecovery; + } + else if (exception.ErrorCode == 11004) + { + netDbErrorCode = NetDbError.NoData; + } + else if (exception.ErrorCode == 10060) + { + errno = GaiError.Again; + } + } + } + else + { + netDbErrorCode = NetDbError.HostNotFound; + } + + if (hostEntry != null) + { + errno = GaiError.Success; + + List addresses = GetIpv4Addresses(hostEntry); + + if (addresses.Count == 0) + { + errno = GaiError.NoData; + netDbErrorCode = NetDbError.NoAddress; + } + else + { + serializedSize = SerializeHostEnt(context, hostEntry, addresses); + } + } + + context.ResponseData.Write((int)netDbErrorCode); + context.ResponseData.Write((int)errno); + context.ResponseData.Write(serializedSize); + + return ResultCode.Success; + } + + [Command(3)] + // GetHostByAddr(u32, u32, u32, u64, pid, buffer) -> (u32, u32, u32, buffer) + public ResultCode GetHostByAddress(ServiceCtx context) + { + byte[] rawIp = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size); + + // TODO: use params + uint socketLength = context.RequestData.ReadUInt32(); + uint type = context.RequestData.ReadUInt32(); + int timeOut = context.RequestData.ReadInt32(); + ulong pidPlaceholder = context.RequestData.ReadUInt64(); + + IPHostEntry hostEntry = null; + + NetDbError netDbErrorCode = NetDbError.Success; + GaiError errno = GaiError.AddressFamily; + long serializedSize = 0; + + if (rawIp.Length == 4) + { + try + { + IPAddress address = new IPAddress(rawIp); + + hostEntry = Dns.GetHostEntry(address); + } + catch (SocketException exception) + { + netDbErrorCode = NetDbError.Internal; + if (exception.ErrorCode == 11001) + { + netDbErrorCode = NetDbError.HostNotFound; + errno = GaiError.NoData; + } + else if (exception.ErrorCode == 11002) + { + netDbErrorCode = NetDbError.TryAgain; + } + else if (exception.ErrorCode == 11003) + { + netDbErrorCode = NetDbError.NoRecovery; + } + else if (exception.ErrorCode == 11004) + { + netDbErrorCode = NetDbError.NoData; + } + else if (exception.ErrorCode == 10060) + { + errno = GaiError.Again; + } + } + } + else + { + netDbErrorCode = NetDbError.NoAddress; + } + + if (hostEntry != null) + { + errno = GaiError.Success; + serializedSize = SerializeHostEnt(context, hostEntry, GetIpv4Addresses(hostEntry)); + } + + context.ResponseData.Write((int)netDbErrorCode); + context.ResponseData.Write((int)errno); + context.ResponseData.Write(serializedSize); + + return ResultCode.Success; + } + + [Command(4)] + // GetHostStringError(u32) -> buffer + public ResultCode GetHostStringError(ServiceCtx context) + { + ResultCode resultCode = ResultCode.NotAllocated; + NetDbError errorCode = (NetDbError)context.RequestData.ReadInt32(); + string errorString = GetHostStringErrorFromErrorCode(errorCode); + + if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size) + { + resultCode = 0; + context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0')); + } + + return resultCode; + } + + [Command(5)] + // GetGaiStringError(u32) -> buffer + public ResultCode GetGaiStringError(ServiceCtx context) + { + ResultCode resultCode = ResultCode.NotAllocated; + GaiError errorCode = (GaiError)context.RequestData.ReadInt32(); + string errorString = GetGaiStringErrorFromErrorCode(errorCode); + + if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size) + { + resultCode = 0; + context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0')); + } + + return resultCode; + } + + [Command(8)] + // RequestCancelHandle(u64, pid) -> u32 + public ResultCode RequestCancelHandle(ServiceCtx context) + { + ulong unknown0 = context.RequestData.ReadUInt64(); + + context.ResponseData.Write(0); + + Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); + + return ResultCode.Success; + } + + [Command(9)] + // CancelSocketCall(u32, u64, pid) + public ResultCode CancelSocketCall(ServiceCtx context) + { + uint unknown0 = context.RequestData.ReadUInt32(); + ulong unknown1 = context.RequestData.ReadUInt64(); + + Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0, unknown1 }); + + return ResultCode.Success; + } + + [Command(11)] + // ClearDnsAddresses(u32) + public ResultCode ClearDnsAddresses(ServiceCtx context) + { + uint unknown0 = context.RequestData.ReadUInt32(); + + Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 }); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs new file mode 100644 index 00000000..f9f28b44 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres +{ + enum GaiError + { + Success, + AddressFamily, + Again, + BadFlags, + Fail, + Family, + Memory, + NoData, + NoName, + Service, + SocketType, + System, + BadHints, + Protocol, + Overflow, + Max + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs new file mode 100644 index 00000000..3c04c049 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres +{ + enum NetDbError + { + Internal = -1, + Success, + HostNotFound, + TryAgain, + NoRecovery, + NoData, + NoAddress = NoData + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs new file mode 100644 index 00000000..b4aebc7e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Sm +{ + [Service("spl:")] + [Service("spl:es")] + [Service("spl:fs")] + [Service("spl:manu")] + [Service("spl:mig")] + [Service("spl:ssl")] + class IGeneralInterface : IpcService + { + public IGeneralInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Srepo/ISrepoService.cs b/Ryujinx.HLE/HOS/Services/Srepo/ISrepoService.cs new file mode 100644 index 00000000..167dea67 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Srepo/ISrepoService.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Srepo +{ + [Service("srepo:a")] // 5.0.0+ + [Service("srepo:u")] // 5.0.0+ + class ISrepoService : IpcService + { + public ISrepoService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs b/Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs deleted file mode 100644 index e70c2421..00000000 --- a/Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Ssl -{ - class ISslContext : IpcService - { - public ISslContext() { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs index 43e4bc7f..2f4b93ca 100644 --- a/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs +++ b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Ssl.SslService; namespace Ryujinx.HLE.HOS.Services.Ssl { diff --git a/Ryujinx.HLE/HOS/Services/Ssl/SslService/ISslContext.cs b/Ryujinx.HLE/HOS/Services/Ssl/SslService/ISslContext.cs new file mode 100644 index 00000000..ef788175 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ssl/SslService/ISslContext.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Ssl.SslService +{ + class ISslContext : IpcService + { + public ISslContext() { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs deleted file mode 100644 index c70819c0..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Ryujinx.HLE.Utilities; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.Clock -{ - [StructLayout(LayoutKind.Sequential)] - struct TimeSpanType - { - private const long NanoSecondsPerSecond = 1000000000; - - public long NanoSeconds; - - public TimeSpanType(long nanoSeconds) - { - NanoSeconds = nanoSeconds; - } - - public long ToSeconds() - { - return NanoSeconds / NanoSecondsPerSecond; - } - - public static TimeSpanType FromSeconds(long seconds) - { - return new TimeSpanType(seconds * NanoSecondsPerSecond); - } - - public static TimeSpanType FromTicks(ulong ticks, ulong frequency) - { - return FromSeconds((long)ticks / (long)frequency); - } - } - - [StructLayout(LayoutKind.Sequential)] - struct SteadyClockTimePoint - { - public long TimePoint; - public UInt128 ClockSourceId; - - public ResultCode GetSpanBetween(SteadyClockTimePoint other, out long outSpan) - { - outSpan = 0; - - if (ClockSourceId == other.ClockSourceId) - { - try - { - outSpan = checked(other.TimePoint - TimePoint); - - return ResultCode.Success; - } - catch (OverflowException) - { - return ResultCode.Overflow; - } - } - - return ResultCode.Overflow; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct SystemClockContext - { - public long Offset; - public SteadyClockTimePoint SteadyTimePoint; - } - - [StructLayout(LayoutKind.Sequential, Size = 0xD0)] - struct ClockSnapshot - { - public SystemClockContext UserContext; - public SystemClockContext NetworkContext; - public long UserTime; - public long NetworkTime; - public CalendarTime UserCalendarTime; - public CalendarTime NetworkCalendarTime; - public CalendarAdditionalInfo UserCalendarAdditionalTime; - public CalendarAdditionalInfo NetworkCalendarAdditionalTime; - public SteadyClockTimePoint SteadyClockTimePoint; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)] - public char[] LocationName; - - [MarshalAs(UnmanagedType.I1)] - public bool IsAutomaticCorrectionEnabled; - public byte Type; - public ushort Unknown; - - public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context) - { - currentTime = 0; - - if (steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId) - { - currentTime = steadyClockTimePoint.TimePoint + context.Offset; - - return ResultCode.Success; - } - - return ResultCode.TimeMismatch; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index 5037fb60..cc21dd9a 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { class StandardNetworkSystemClockCore : SystemClockCore { - private TimeSpanType _standardNetworkClockSufficientAccuracy; + private TimeSpanType _standardNetworkClockSufficientAccuracy; private static StandardNetworkSystemClockCore _instance; diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs index 5b2d6c84..1bc5bee7 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs @@ -1,5 +1,5 @@ using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Bpc; +using Ryujinx.HLE.HOS.Services.Pcv.Bpc; namespace Ryujinx.HLE.HOS.Services.Time.Clock { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs index 6cd4c80b..e5baba25 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs @@ -1,5 +1,4 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Kernel.Threading; namespace Ryujinx.HLE.HOS.Services.Time.Clock { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs new file mode 100644 index 00000000..df1f151f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs @@ -0,0 +1,41 @@ +using Ryujinx.HLE.HOS.Services.Time.TimeZone; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential, Size = 0xD0)] + struct ClockSnapshot + { + public SystemClockContext UserContext; + public SystemClockContext NetworkContext; + public long UserTime; + public long NetworkTime; + public CalendarTime UserCalendarTime; + public CalendarTime NetworkCalendarTime; + public CalendarAdditionalInfo UserCalendarAdditionalTime; + public CalendarAdditionalInfo NetworkCalendarAdditionalTime; + public SteadyClockTimePoint SteadyClockTimePoint; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)] + public char[] LocationName; + + [MarshalAs(UnmanagedType.I1)] + public bool IsAutomaticCorrectionEnabled; + public byte Type; + public ushort Unknown; + + public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context) + { + currentTime = 0; + + if (steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId) + { + currentTime = steadyClockTimePoint.TimePoint + context.Offset; + + return ResultCode.Success; + } + + return ResultCode.TimeMismatch; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs new file mode 100644 index 00000000..0055b5ea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs @@ -0,0 +1,34 @@ +using Ryujinx.HLE.Utilities; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct SteadyClockTimePoint + { + public long TimePoint; + public UInt128 ClockSourceId; + + public ResultCode GetSpanBetween(SteadyClockTimePoint other, out long outSpan) + { + outSpan = 0; + + if (ClockSourceId == other.ClockSourceId) + { + try + { + outSpan = checked(other.TimePoint - TimePoint); + + return ResultCode.Success; + } + catch (OverflowException) + { + return ResultCode.Overflow; + } + } + + return ResultCode.Overflow; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs new file mode 100644 index 00000000..38e10480 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct SystemClockContext + { + public long Offset; + public SteadyClockTimePoint SteadyTimePoint; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs new file mode 100644 index 00000000..93579709 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct TimeSpanType + { + private const long NanoSecondsPerSecond = 1000000000; + + public long NanoSeconds; + + public TimeSpanType(long nanoSeconds) + { + NanoSeconds = nanoSeconds; + } + + public long ToSeconds() + { + return NanoSeconds / NanoSecondsPerSecond; + } + + public static TimeSpanType FromSeconds(long seconds) + { + return new TimeSpanType(seconds * NanoSecondsPerSecond); + } + + public static TimeSpanType FromTicks(ulong ticks, ulong frequency) + { + return FromSeconds((long)ticks / (long)frequency); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs b/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs new file mode 100644 index 00000000..092fa8ce --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:al")] // 9.0.0+ + class IAlarmService : IpcService + { + public IAlarmService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs b/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs new file mode 100644 index 00000000..cb10da47 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:m")] // 9.0.0+ + class IPowerStateRequestHandler : IpcService + { + public IPowerStateRequestHandler(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs index d9c5b4f2..0cfdebcf 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Time.Clock; +using Ryujinx.HLE.HOS.Services.Time.StaticService; using Ryujinx.HLE.HOS.Services.Time.TimeZone; using System; using System.Diagnostics; @@ -14,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.Time [Service("time:a", TimePermissions.Applet)] [Service("time:s", TimePermissions.System)] [Service("time:u", TimePermissions.User)] + [Service("time:p", TimePermissions.System)] // 9.0.0+ - TODO: Fix the permission. class IStaticService : IpcService { private TimePermissions _permissions; diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs deleted file mode 100644 index 7e3edcef..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Time.Clock; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ISteadyClock : IpcService - { - [Command(0)] - // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint - public ResultCode GetCurrentTimePoint(ServiceCtx context) - { - SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); - - context.ResponseData.WriteStruct(currentTimePoint); - - return ResultCode.Success; - } - - [Command(1)] - // GetTestOffset() -> nn::TimeSpanType - public ResultCode GetTestOffset(ServiceCtx context) - { - context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset()); - - return ResultCode.Success; - } - - [Command(2)] - // SetTestOffset(nn::TimeSpanType) - public ResultCode SetTestOffset(ServiceCtx context) - { - TimeSpanType testOffset = context.RequestData.ReadStruct(); - - StandardSteadyClockCore.Instance.SetTestOffset(testOffset); - - return 0; - } - - [Command(100)] // 2.0.0+ - // GetRtcValue() -> u64 - public ResultCode GetRtcValue(ServiceCtx context) - { - ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue); - - if (result == ResultCode.Success) - { - context.ResponseData.Write(rtcValue); - } - - return result; - } - - [Command(101)] // 2.0.0+ - // IsRtcResetDetected() -> bool - public ResultCode IsRtcResetDetected(ServiceCtx context) - { - context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected()); - - return ResultCode.Success; - } - - [Command(102)] // 2.0.0+ - // GetSetupResultValue() -> u32 - public ResultCode GetSetupResultValue(ServiceCtx context) - { - context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue()); - - return ResultCode.Success; - } - - [Command(200)] // 3.0.0+ - // GetInternalOffset() -> nn::TimeSpanType - public ResultCode GetInternalOffset(ServiceCtx context) - { - context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset()); - - return ResultCode.Success; - } - - [Command(201)] // 3.0.0-3.0.2 - // SetInternalOffset(nn::TimeSpanType) - public ResultCode SetInternalOffset(ServiceCtx context) - { - TimeSpanType internalOffset = context.RequestData.ReadStruct(); - - StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs deleted file mode 100644 index d496dcdc..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Time.Clock; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ISystemClock : IpcService - { - private SystemClockCore _clockCore; - private bool _writePermission; - - public ISystemClock(SystemClockCore clockCore, bool writePermission) - { - _clockCore = clockCore; - _writePermission = writePermission; - } - - [Command(0)] - // GetCurrentTime() -> nn::time::PosixTime - public ResultCode GetCurrentTime(ServiceCtx context) - { - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); - - ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); - - if (result == ResultCode.Success) - { - result = ResultCode.TimeMismatch; - - if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) - { - long posixTime = clockContext.Offset + currentTimePoint.TimePoint; - - context.ResponseData.Write(posixTime); - - result = 0; - } - } - - return result; - } - - [Command(1)] - // SetCurrentTime(nn::time::PosixTime) - public ResultCode SetCurrentTime(ServiceCtx context) - { - if (!_writePermission) - { - return ResultCode.PermissionDenied; - } - - long posixTime = context.RequestData.ReadInt64(); - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); - - SystemClockContext clockContext = new SystemClockContext() - { - Offset = posixTime - currentTimePoint.TimePoint, - SteadyTimePoint = currentTimePoint - }; - - ResultCode result = _clockCore.SetSystemClockContext(clockContext); - - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); - } - - return result; - } - - [Command(2)] - // GetSystemClockContext() -> nn::time::SystemClockContext - public ResultCode GetSystemClockContext(ServiceCtx context) - { - ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); - - if (result == ResultCode.Success) - { - context.ResponseData.WriteStruct(clockContext); - } - - return result; - } - - [Command(3)] - // SetSystemClockContext(nn::time::SystemClockContext) - public ResultCode SetSystemClockContext(ServiceCtx context) - { - if (!_writePermission) - { - return ResultCode.PermissionDenied; - } - - SystemClockContext clockContext = context.RequestData.ReadStruct(); - - ResultCode result = _clockCore.SetSystemClockContext(clockContext); - - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs new file mode 100644 index 00000000..514e901e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:su")] // 9.0.0+ + class ITimeServiceManager : IpcService + { + public ITimeServiceManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs deleted file mode 100644 index b820de38..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs +++ /dev/null @@ -1,218 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ITimeZoneService : IpcService - { - public ITimeZoneService() { } - - [Command(0)] - // GetDeviceLocationName() -> nn::time::LocationName - public ResultCode GetDeviceLocationName(ServiceCtx context) - { - char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray(); - - int padding = 0x24 - tzName.Length; - - if (padding < 0) - { - return ResultCode.LocationNameTooLong; - } - - context.ResponseData.Write(tzName); - - for (int index = 0; index < padding; index++) - { - context.ResponseData.Write((byte)0); - } - - return ResultCode.Success; - } - - [Command(1)] - // SetDeviceLocationName(nn::time::LocationName) - public ResultCode SetDeviceLocationName(ServiceCtx context) - { - string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); - - return TimeZoneManager.Instance.SetDeviceLocationName(locationName); - } - - [Command(2)] - // GetTotalLocationNameCount() -> u32 - public ResultCode GetTotalLocationNameCount(ServiceCtx context) - { - context.ResponseData.Write(TimeZoneManager.Instance.GetTotalLocationNameCount()); - - return ResultCode.Success; - } - - [Command(3)] - // LoadLocationNameList(u32 index) -> (u32 outCount, buffer) - public ResultCode LoadLocationNameList(ServiceCtx context) - { - uint index = context.RequestData.ReadUInt32(); - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferSize = context.Request.ReceiveBuff[0].Size; - - ResultCode errorCode = TimeZoneManager.Instance.LoadLocationNameList(index, out string[] locationNameArray, (uint)bufferSize / 0x24); - - if (errorCode == 0) - { - uint offset = 0; - - foreach (string locationName in locationNameArray) - { - int padding = 0x24 - locationName.Length; - - if (padding < 0) - { - return ResultCode.LocationNameTooLong; - } - - context.Memory.WriteBytes(bufferPosition + offset, Encoding.ASCII.GetBytes(locationName)); - MemoryHelper.FillWithZeros(context.Memory, bufferPosition + offset + locationName.Length, padding); - - offset += 0x24; - } - - context.ResponseData.Write((uint)locationNameArray.Length); - } - - return errorCode; - } - - [Command(4)] - // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer - public ResultCode LoadTimeZoneRule(ServiceCtx context) - { - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferSize = context.Request.ReceiveBuff[0].Size; - - if (bufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - - string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); - - ResultCode resultCode = TimeZoneManager.Instance.LoadTimeZoneRules(out TimeZoneRule rules, locationName); - - // Write TimeZoneRule if success - if (resultCode == 0) - { - MemoryHelper.Write(context.Memory, bufferPosition, rules); - } - - return resultCode; - } - - [Command(100)] - // ToCalendarTime(nn::time::PosixTime time, buffer rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) - public ResultCode ToCalendarTime(ServiceCtx context) - { - long posixTime = context.RequestData.ReadInt64(); - long bufferPosition = context.Request.SendBuff[0].Position; - long bufferSize = context.Request.SendBuff[0].Size; - - if (bufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - TimeZoneRule rules = MemoryHelper.Read(context.Memory, bufferPosition); - - ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar); - - if (resultCode == 0) - { - context.ResponseData.WriteStruct(calendar); - } - - return resultCode; - } - - [Command(101)] - // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) - public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context) - { - long posixTime = context.RequestData.ReadInt64(); - - ResultCode resultCode = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar); - - if (resultCode == 0) - { - context.ResponseData.WriteStruct(calendar); - } - - return resultCode; - } - - [Command(201)] - // ToPosixTime(nn::time::CalendarTime calendarTime, buffer rules) -> (u32 outCount, buffer) - public ResultCode ToPosixTime(ServiceCtx context) - { - long inBufferPosition = context.Request.SendBuff[0].Position; - long inBufferSize = context.Request.SendBuff[0].Size; - - CalendarTime calendarTime = context.RequestData.ReadStruct(); - - if (inBufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - TimeZoneRule rules = MemoryHelper.Read(context.Memory, inBufferPosition); - - ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime); - - if (resultCode == 0) - { - long outBufferPosition = context.Request.RecvListBuff[0].Position; - long outBufferSize = context.Request.RecvListBuff[0].Size; - - context.Memory.WriteInt64(outBufferPosition, posixTime); - context.ResponseData.Write(1); - } - - return resultCode; - } - - [Command(202)] - // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer) - public ResultCode ToPosixTimeWithMyRule(ServiceCtx context) - { - CalendarTime calendarTime = context.RequestData.ReadStruct(); - - ResultCode resultCode = TimeZoneManager.Instance.ToPosixTimeWithMyRules(calendarTime, out long posixTime); - - if (resultCode == 0) - { - long outBufferPosition = context.Request.RecvListBuff[0].Position; - long outBufferSize = context.Request.RecvListBuff[0].Size; - - context.Memory.WriteInt64(outBufferPosition, posixTime); - - // There could be only one result on one calendar as leap seconds aren't supported. - context.ResponseData.Write(1); - } - - return resultCode; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs deleted file mode 100644 index 9a83b82b..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct TimeTypeInfo - { - public int GmtOffset; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - char[] Padding1; - - public int AbbreviationListIndex; - - [MarshalAs(UnmanagedType.I1)] - public bool IsStandardTimeDaylight; - - [MarshalAs(UnmanagedType.I1)] - public bool IsGMT; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - char[] Padding2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] - struct TimeZoneRule - { - public const int TzMaxTypes = 128; - public const int TzMaxChars = 50; - public const int TzMaxLeaps = 50; - public const int TzMaxTimes = 1000; - public const int TzNameMax = 255; - public const int TzCharsArraySize = 2 * (TzNameMax + 1); - - public int TimeCount; - public int TypeCount; - public int CharCount; - - [MarshalAs(UnmanagedType.I1)] - public bool GoBack; - - [MarshalAs(UnmanagedType.I1)] - public bool GoAhead; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] - public long[] Ats; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] - public byte[] Types; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)] - public TimeTypeInfo[] Ttis; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)] - public char[] Chars; - - public int DefaultType; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)] - struct TzifHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public char[] Magic; - - public char Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] - public byte[] Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TtisGMTCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TtisSTDCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] LeapCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TimeCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TypeCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] CharCount; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x8)] - struct CalendarTime - { - public short Year; - public sbyte Month; - public sbyte Day; - public sbyte Hour; - public sbyte Minute; - public sbyte Second; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x18, CharSet = CharSet.Ansi)] - struct CalendarAdditionalInfo - { - public uint DayOfWeek; - public uint DayOfYear; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public char[] TimezoneName; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - char[] Padding; - - public int GmtOffset; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x20, CharSet = CharSet.Ansi)] - struct CalendarInfo - { - public CalendarTime Time; - public CalendarAdditionalInfo AdditionalInfo; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs new file mode 100644 index 00000000..31f119df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs @@ -0,0 +1,91 @@ +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Services.Time.Clock; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ISteadyClock : IpcService + { + [Command(0)] + // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint + public ResultCode GetCurrentTimePoint(ServiceCtx context) + { + SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); + + context.ResponseData.WriteStruct(currentTimePoint); + + return ResultCode.Success; + } + + [Command(1)] + // GetTestOffset() -> nn::TimeSpanType + public ResultCode GetTestOffset(ServiceCtx context) + { + context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset()); + + return ResultCode.Success; + } + + [Command(2)] + // SetTestOffset(nn::TimeSpanType) + public ResultCode SetTestOffset(ServiceCtx context) + { + TimeSpanType testOffset = context.RequestData.ReadStruct(); + + StandardSteadyClockCore.Instance.SetTestOffset(testOffset); + + return 0; + } + + [Command(100)] // 2.0.0+ + // GetRtcValue() -> u64 + public ResultCode GetRtcValue(ServiceCtx context) + { + ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue); + + if (result == ResultCode.Success) + { + context.ResponseData.Write(rtcValue); + } + + return result; + } + + [Command(101)] // 2.0.0+ + // IsRtcResetDetected() -> bool + public ResultCode IsRtcResetDetected(ServiceCtx context) + { + context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected()); + + return ResultCode.Success; + } + + [Command(102)] // 2.0.0+ + // GetSetupResultValue() -> u32 + public ResultCode GetSetupResultValue(ServiceCtx context) + { + context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue()); + + return ResultCode.Success; + } + + [Command(200)] // 3.0.0+ + // GetInternalOffset() -> nn::TimeSpanType + public ResultCode GetInternalOffset(ServiceCtx context) + { + context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset()); + + return ResultCode.Success; + } + + [Command(201)] // 3.0.0-3.0.2 + // SetInternalOffset(nn::TimeSpanType) + public ResultCode SetInternalOffset(ServiceCtx context) + { + TimeSpanType internalOffset = context.RequestData.ReadStruct(); + + StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs new file mode 100644 index 00000000..0d866177 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs @@ -0,0 +1,107 @@ +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Services.Time.Clock; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ISystemClock : IpcService + { + private SystemClockCore _clockCore; + private bool _writePermission; + + public ISystemClock(SystemClockCore clockCore, bool writePermission) + { + _clockCore = clockCore; + _writePermission = writePermission; + } + + [Command(0)] + // GetCurrentTime() -> nn::time::PosixTime + public ResultCode GetCurrentTime(ServiceCtx context) + { + SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); + + ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); + + if (result == ResultCode.Success) + { + result = ResultCode.TimeMismatch; + + if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) + { + long posixTime = clockContext.Offset + currentTimePoint.TimePoint; + + context.ResponseData.Write(posixTime); + + result = 0; + } + } + + return result; + } + + [Command(1)] + // SetCurrentTime(nn::time::PosixTime) + public ResultCode SetCurrentTime(ServiceCtx context) + { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + long posixTime = context.RequestData.ReadInt64(); + SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); + + SystemClockContext clockContext = new SystemClockContext() + { + Offset = posixTime - currentTimePoint.TimePoint, + SteadyTimePoint = currentTimePoint + }; + + ResultCode result = _clockCore.SetSystemClockContext(clockContext); + + if (result == ResultCode.Success) + { + result = _clockCore.Flush(clockContext); + } + + return result; + } + + [Command(2)] + // GetSystemClockContext() -> nn::time::SystemClockContext + public ResultCode GetSystemClockContext(ServiceCtx context) + { + ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); + + if (result == ResultCode.Success) + { + context.ResponseData.WriteStruct(clockContext); + } + + return result; + } + + [Command(3)] + // SetSystemClockContext(nn::time::SystemClockContext) + public ResultCode SetSystemClockContext(ServiceCtx context) + { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + SystemClockContext clockContext = context.RequestData.ReadStruct(); + + ResultCode result = _clockCore.SetSystemClockContext(clockContext); + + if (result == ResultCode.Success) + { + result = _clockCore.Flush(clockContext); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs new file mode 100644 index 00000000..c65107df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs @@ -0,0 +1,218 @@ +using ARMeilleure.Memory; +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Time.TimeZone; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ITimeZoneService : IpcService + { + public ITimeZoneService() { } + + [Command(0)] + // GetDeviceLocationName() -> nn::time::LocationName + public ResultCode GetDeviceLocationName(ServiceCtx context) + { + char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray(); + + int padding = 0x24 - tzName.Length; + + if (padding < 0) + { + return ResultCode.LocationNameTooLong; + } + + context.ResponseData.Write(tzName); + + for (int index = 0; index < padding; index++) + { + context.ResponseData.Write((byte)0); + } + + return ResultCode.Success; + } + + [Command(1)] + // SetDeviceLocationName(nn::time::LocationName) + public ResultCode SetDeviceLocationName(ServiceCtx context) + { + string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); + + return TimeZoneManager.Instance.SetDeviceLocationName(locationName); + } + + [Command(2)] + // GetTotalLocationNameCount() -> u32 + public ResultCode GetTotalLocationNameCount(ServiceCtx context) + { + context.ResponseData.Write(TimeZoneManager.Instance.GetTotalLocationNameCount()); + + return ResultCode.Success; + } + + [Command(3)] + // LoadLocationNameList(u32 index) -> (u32 outCount, buffer) + public ResultCode LoadLocationNameList(ServiceCtx context) + { + uint index = context.RequestData.ReadUInt32(); + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferSize = context.Request.ReceiveBuff[0].Size; + + ResultCode errorCode = TimeZoneManager.Instance.LoadLocationNameList(index, out string[] locationNameArray, (uint)bufferSize / 0x24); + + if (errorCode == 0) + { + uint offset = 0; + + foreach (string locationName in locationNameArray) + { + int padding = 0x24 - locationName.Length; + + if (padding < 0) + { + return ResultCode.LocationNameTooLong; + } + + context.Memory.WriteBytes(bufferPosition + offset, Encoding.ASCII.GetBytes(locationName)); + MemoryHelper.FillWithZeros(context.Memory, bufferPosition + offset + locationName.Length, padding); + + offset += 0x24; + } + + context.ResponseData.Write((uint)locationNameArray.Length); + } + + return errorCode; + } + + [Command(4)] + // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer + public ResultCode LoadTimeZoneRule(ServiceCtx context) + { + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferSize = context.Request.ReceiveBuff[0].Size; + + if (bufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + + string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); + + ResultCode resultCode = TimeZoneManager.Instance.LoadTimeZoneRules(out TimeZoneRule rules, locationName); + + // Write TimeZoneRule if success + if (resultCode == 0) + { + MemoryHelper.Write(context.Memory, bufferPosition, rules); + } + + return resultCode; + } + + [Command(100)] + // ToCalendarTime(nn::time::PosixTime time, buffer rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) + public ResultCode ToCalendarTime(ServiceCtx context) + { + long posixTime = context.RequestData.ReadInt64(); + long bufferPosition = context.Request.SendBuff[0].Position; + long bufferSize = context.Request.SendBuff[0].Size; + + if (bufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + TimeZoneRule rules = MemoryHelper.Read(context.Memory, bufferPosition); + + ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar); + + if (resultCode == 0) + { + context.ResponseData.WriteStruct(calendar); + } + + return resultCode; + } + + [Command(101)] + // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) + public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context) + { + long posixTime = context.RequestData.ReadInt64(); + + ResultCode resultCode = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar); + + if (resultCode == 0) + { + context.ResponseData.WriteStruct(calendar); + } + + return resultCode; + } + + [Command(201)] + // ToPosixTime(nn::time::CalendarTime calendarTime, buffer rules) -> (u32 outCount, buffer) + public ResultCode ToPosixTime(ServiceCtx context) + { + long inBufferPosition = context.Request.SendBuff[0].Position; + long inBufferSize = context.Request.SendBuff[0].Size; + + CalendarTime calendarTime = context.RequestData.ReadStruct(); + + if (inBufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + TimeZoneRule rules = MemoryHelper.Read(context.Memory, inBufferPosition); + + ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime); + + if (resultCode == 0) + { + long outBufferPosition = context.Request.RecvListBuff[0].Position; + long outBufferSize = context.Request.RecvListBuff[0].Size; + + context.Memory.WriteInt64(outBufferPosition, posixTime); + context.ResponseData.Write(1); + } + + return resultCode; + } + + [Command(202)] + // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer) + public ResultCode ToPosixTimeWithMyRule(ServiceCtx context) + { + CalendarTime calendarTime = context.RequestData.ReadStruct(); + + ResultCode resultCode = TimeZoneManager.Instance.ToPosixTimeWithMyRules(calendarTime, out long posixTime); + + if (resultCode == 0) + { + long outBufferPosition = context.Request.RecvListBuff[0].Position; + long outBufferSize = context.Request.RecvListBuff[0].Size; + + context.Memory.WriteInt64(outBufferPosition, posixTime); + + // There could be only one result on one calendar as leap seconds aren't supported. + context.ResponseData.Write(1); + } + + return resultCode; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs b/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs deleted file mode 100644 index 823c8288..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - [Flags] - enum TimePermissions - { - LocalSystemClockWritableMask = 0x1, - UserSystemClockWritableMask = 0x2, - NetworkSystemClockWritableMask = 0x4, - UnknownPermissionMask = 0x8, - - User = 0, - Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, - System = NetworkSystemClockWritableMask - } -} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs index 4b482689..3a98013e 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs @@ -1,10 +1,11 @@ -using System; +using Ryujinx.Common; +using Ryujinx.HLE.Utilities; +using System; using System.IO; using System.Runtime.InteropServices; using System.Text; -using Ryujinx.Common; -using Ryujinx.HLE.Utilities; -using static Ryujinx.HLE.HOS.Services.Time.TimeZoneRule; + +using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { @@ -238,9 +239,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { seconds = 0; - int num; - bool isValid = GetNum(name, ref namePosition, out num, 0, HoursPerDays * DaysPerWekk - 1); + bool isValid = GetNum(name, ref namePosition, out int num, 0, HoursPerDays * DaysPerWekk - 1); if (!isValid) { return false; diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs index cf27639b..2497f6a3 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs @@ -1,15 +1,15 @@ -using LibHac.Fs.NcaUtils; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; -using LibHac.Fs; using System.IO; -using System.Collections.Generic; -using TimeZoneConverter.Posix; using TimeZoneConverter; +using TimeZoneConverter.Posix; -using static Ryujinx.HLE.HOS.Services.Time.TimeZoneRule; +using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs new file mode 100644 index 00000000..ef9b87e7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x18, CharSet = CharSet.Ansi)] + struct CalendarAdditionalInfo + { + public uint DayOfWeek; + public uint DayOfYear; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public char[] TimezoneName; + + [MarshalAs(UnmanagedType.I1)] + public bool IsDaySavingTime; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public char[] Padding; + + public int GmtOffset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs new file mode 100644 index 00000000..68e6245b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x20, CharSet = CharSet.Ansi)] + struct CalendarInfo + { + public CalendarTime Time; + public CalendarAdditionalInfo AdditionalInfo; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs new file mode 100644 index 00000000..d594223d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x8)] + struct CalendarTime + { + public short Year; + public sbyte Month; + public sbyte Day; + public sbyte Hour; + public sbyte Minute; + public sbyte Second; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs new file mode 100644 index 00000000..399e0700 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct TimeTypeInfo + { + public int GmtOffset; + + [MarshalAs(UnmanagedType.I1)] + public bool IsDaySavingTime; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public char[] Padding1; + + public int AbbreviationListIndex; + + [MarshalAs(UnmanagedType.I1)] + public bool IsStandardTimeDaylight; + + [MarshalAs(UnmanagedType.I1)] + public bool IsGMT; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public char[] Padding2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs new file mode 100644 index 00000000..1af7a81a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] + struct TimeZoneRule + { + public const int TzMaxTypes = 128; + public const int TzMaxChars = 50; + public const int TzMaxLeaps = 50; + public const int TzMaxTimes = 1000; + public const int TzNameMax = 255; + public const int TzCharsArraySize = 2 * (TzNameMax + 1); + + public int TimeCount; + public int TypeCount; + public int CharCount; + + [MarshalAs(UnmanagedType.I1)] + public bool GoBack; + + [MarshalAs(UnmanagedType.I1)] + public bool GoAhead; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] + public long[] Ats; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] + public byte[] Types; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)] + public TimeTypeInfo[] Ttis; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)] + public char[] Chars; + + public int DefaultType; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs new file mode 100644 index 00000000..1a033c33 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)] + struct TzifHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public char[] Magic; + + public char Version; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TtisGMTCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TtisSTDCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] LeapCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TimeCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TypeCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] CharCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs new file mode 100644 index 00000000..823c8288 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs @@ -0,0 +1,17 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Flags] + enum TimePermissions + { + LocalSystemClockWritableMask = 0x1, + UserSystemClockWritableMask = 0x2, + NetworkSystemClockWritableMask = 0x4, + UnknownPermissionMask = 0x8, + + User = 0, + Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, + System = NetworkSystemClockWritableMask + } +} diff --git a/Ryujinx.HLE/HOS/Services/Usb/IClientRootSession.cs b/Ryujinx.HLE/HOS/Services/Usb/IClientRootSession.cs new file mode 100644 index 00000000..56b12af0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IClientRootSession.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:hs")] + [Service("usb:hs:a")] // 7.0.0+ + class IClientRootSession : IpcService + { + public IClientRootSession(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IDsService.cs b/Ryujinx.HLE/HOS/Services/Usb/IDsService.cs new file mode 100644 index 00000000..4dbb6fc1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IDsService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:ds")] + class IDsService : IpcService + { + public IDsService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IPdCradleManager.cs b/Ryujinx.HLE/HOS/Services/Usb/IPdCradleManager.cs new file mode 100644 index 00000000..cecdbc31 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IPdCradleManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:pd:c")] + class IPdCradleManager : IpcService + { + public IPdCradleManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IPdManager.cs b/Ryujinx.HLE/HOS/Services/Usb/IPdManager.cs new file mode 100644 index 00000000..1fb574d2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IPdManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:pd")] + class IPdManager : IpcService + { + public IPdManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IPmService.cs b/Ryujinx.HLE/HOS/Services/Usb/IPmService.cs new file mode 100644 index 00000000..38beee07 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IPmService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:pm")] + class IPmService : IpcService + { + public IPmService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IUnknown1.cs b/Ryujinx.HLE/HOS/Services/Usb/IUnknown1.cs new file mode 100644 index 00000000..0981e4ff --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IUnknown1.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:qdb")] // 7.0.0+ + class IUnknown1 : IpcService + { + public IUnknown1(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Usb/IUnknown2.cs b/Ryujinx.HLE/HOS/Services/Usb/IUnknown2.cs new file mode 100644 index 00000000..563696bb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Usb/IUnknown2.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Usb +{ + [Service("usb:obsv")] // 8.0.0+ + class IUnknown2 : IpcService + { + public IUnknown2(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs b/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs deleted file mode 100644 index 2522dffc..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs +++ /dev/null @@ -1,366 +0,0 @@ -// ReSharper disable InconsistentNaming -namespace Ryujinx.HLE.HOS.Services.Android -{ - class ColorShift - { - public const int Swizzle = 16; - public const int DataType = 14; - public const int Space = 32; - public const int Component = 8; - } - - enum ColorSwizzle - { - XYZW = 0x688 << ColorShift.Swizzle, - ZYXW = 0x60a << ColorShift.Swizzle, - WZYX = 0x053 << ColorShift.Swizzle, - YZWX = 0x0d1 << ColorShift.Swizzle, - XYZ1 = 0xa88 << ColorShift.Swizzle, - YZW1 = 0xad1 << ColorShift.Swizzle, - XXX1 = 0xa00 << ColorShift.Swizzle, - XZY1 = 0xa50 << ColorShift.Swizzle, - ZYX1 = 0xa0a << ColorShift.Swizzle, - WZY1 = 0xa53 << ColorShift.Swizzle, - X000 = 0x920 << ColorShift.Swizzle, - Y000 = 0x921 << ColorShift.Swizzle, - XY01 = 0xb08 << ColorShift.Swizzle, - X001 = 0xb20 << ColorShift.Swizzle, - X00X = 0x121 << ColorShift.Swizzle, - X00Y = 0x320 << ColorShift.Swizzle, - _0YX0 = 0x80c << ColorShift.Swizzle, - _0ZY0 = 0x814 << ColorShift.Swizzle, - _0XZ0 = 0x884 << ColorShift.Swizzle, - _0X00 = 0x904 << ColorShift.Swizzle, - _00X0 = 0x824 << ColorShift.Swizzle, - _000X = 0x124 << ColorShift.Swizzle, - _0XY0 = 0x844 << ColorShift.Swizzle, - XXXY = 0x200 << ColorShift.Swizzle, - YYYX = 0x049 << ColorShift.Swizzle - } - - enum ColorBytePerPixel - { - Bpp1 = 1, - Bpp2 = 2, - Bpp4 = 4, - Bpp8 = 8, - Bpp16 = 16, - Bpp24 = 24, - Bpp32 = 32, - Bpp48 = 48, - Bpp64 = 64, - Bpp96 = 96, - Bpp128 = 128 - } - - enum ColorComponent : uint - { - X1 = (0x01 << ColorShift.Component) | ColorBytePerPixel.Bpp1, - X2 = (0x02 << ColorShift.Component) | ColorBytePerPixel.Bpp2, - X4 = (0x03 << ColorShift.Component) | ColorBytePerPixel.Bpp4, - X8 = (0x04 << ColorShift.Component) | ColorBytePerPixel.Bpp8, - Y4X4 = (0x05 << ColorShift.Component) | ColorBytePerPixel.Bpp8, - X3Y3Z2 = (0x06 << ColorShift.Component) | ColorBytePerPixel.Bpp8, - X8Y8 = (0x07 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X8Y8X8Z8 = (0x08 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Y8X8Z8X8 = (0x09 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X16 = (0x0A << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Y2X14 = (0x0B << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Y4X12 = (0x0C << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Y6X10 = (0x0D << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Y8X8 = (0x0E << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X10 = (0x0F << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X12 = (0x10 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - Z5Y5X6 = (0x11 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X5Y6Z5 = (0x12 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X6Y5Z5 = (0x13 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X1Y5Z5W5 = (0x14 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X4Y4Z4W4 = (0x15 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X5Y1Z5W5 = (0x16 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X5Y5Z1W5 = (0x17 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X5Y5Z5W1 = (0x18 << ColorShift.Component) | ColorBytePerPixel.Bpp16, - X8Y8Z8 = (0x19 << ColorShift.Component) | ColorBytePerPixel.Bpp24, - X24 = (0x1A << ColorShift.Component) | ColorBytePerPixel.Bpp24, - X32 = (0x1C << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X16Y16 = (0x1D << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X11Y11Z10 = (0x1E << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X2Y10Z10W10 = (0x20 << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X8Y8Z8W8 = (0x21 << ColorShift.Component) | ColorBytePerPixel.Bpp32, - Y10X10 = (0x22 << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X10Y10Z10W2 = (0x23 << ColorShift.Component) | ColorBytePerPixel.Bpp32, - Y12X12 = (0x24 << ColorShift.Component) | ColorBytePerPixel.Bpp32, - X20Y20Z20 = (0x26 << ColorShift.Component) | ColorBytePerPixel.Bpp64, - X16Y16Z16W16 = (0x27 << ColorShift.Component) | ColorBytePerPixel.Bpp64, - } - - enum ColorDataType - { - Integer = 0x0 << ColorShift.DataType, - Float = 0x1 << ColorShift.DataType, - Stencil = 0x2 << ColorShift.DataType - } - - enum ColorSpace : ulong - { - NonColor = 0x0L << ColorShift.Space, - LinearRGBA = 0x1L << ColorShift.Space, - SRGB = 0x2L << ColorShift.Space, - - RGB709 = 0x3L << ColorShift.Space, - LinearRGB709 = 0x4L << ColorShift.Space, - - LinearScRGB = 0x5L << ColorShift.Space, - - RGB2020 = 0x6L << ColorShift.Space, - LinearRGB2020 = 0x7L << ColorShift.Space, - RGB2020_PQ = 0x8L << ColorShift.Space, - - ColorIndex = 0x9L << ColorShift.Space, - - YCbCr601 = 0xAL << ColorShift.Space, - YCbCr601_RR = 0xBL << ColorShift.Space, - YCbCr601_ER = 0xCL << ColorShift.Space, - YCbCr709 = 0xDL << ColorShift.Space, - YCbCr709_ER = 0xEL << ColorShift.Space, - - BayerRGGB = 0x10L << ColorShift.Space, - BayerBGGR = 0x11L << ColorShift.Space, - BayerGRBG = 0x12L << ColorShift.Space, - BayerGBRG = 0x13L << ColorShift.Space, - - XYZ = 0x14L << ColorShift.Space, - } - - enum ColorFormat : ulong - { - NonColor8 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - NonColor16 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - NonColor24 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X24 | ColorDataType.Integer, - NonColor32 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X32 | ColorDataType.Integer, - X4C4 = ColorSpace.NonColor | ColorSwizzle.Y000 | ColorComponent.Y4X4 | ColorDataType.Integer, - A4L4 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y4X4 | ColorDataType.Integer, - A8L8 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y8X8 | ColorDataType.Integer, - Float_A16L16 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.X16Y16 | ColorDataType.Float, - A1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - A4B4G4R4 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - A5B5G5R1 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - A2B10G10R10 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - A4R4G4B4 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - A5R1G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X5Y1Z5W5 | ColorDataType.Integer, - A2R10G10B10 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A1 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X1 | ColorDataType.Integer, - A2 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X2 | ColorDataType.Integer, - A4 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X4 | ColorDataType.Integer, - A8 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X8 | ColorDataType.Integer, - A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Integer, - A32 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X32 | ColorDataType.Integer, - Float_A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Float, - L4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y4X4 | ColorDataType.Integer, - L8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y8X8 | ColorDataType.Integer, - B4G4R4A4 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - B5G5R1A5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z1W5 | ColorDataType.Integer, - B5G5R5A1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - B8G8R8A8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - B10G10R10A2 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R1G5B5A5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - R4G4B4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - R5G5B5A1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - R8G8B8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - R10G10B10A2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - L1 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X1 | ColorDataType.Integer, - L2 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X2 | ColorDataType.Integer, - L4 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X4 | ColorDataType.Integer, - L8 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X8 | ColorDataType.Integer, - L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Integer, - L32 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X32 | ColorDataType.Integer, - Float_L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Float, - B5G6R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, - B6G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X6Y5Z5 | ColorDataType.Integer, - B5G5R5X1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - B8_G8_R8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - B8G8R8X8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - Float_B10G11R11 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X11Y11Z10 | ColorDataType.Float, - X1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - X8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - R3G3B2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X3Y3Z2 | ColorDataType.Integer, - R5G5B6 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.Z5Y5X6 | ColorDataType.Integer, - R5G6B5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, - R5G5B5X1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - R8_G8_B8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - R8G8B8X8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - X8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - RG8 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.Y8X8 | ColorDataType.Integer, - R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Integer, - Float_R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Float, - R8 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X8 | ColorDataType.Integer, - R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Integer, - Float_R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Float, - A2B10G10R10_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_sRGB = ColorSpace.SRGB | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_709 = ColorSpace.RGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_709 = ColorSpace.RGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_709 = ColorSpace.RGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_scRGB_Linear = ColorSpace.LinearScRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A2B10G10R10_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_2020 = ColorSpace.RGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A2R10G10B10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_2020_PQ = ColorSpace.RGB2020_PQ | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A4I4 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y4X4 | ColorDataType.Integer, - A8I8 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y8X8 | ColorDataType.Integer, - I4A4 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y4X4 | ColorDataType.Integer, - I8A8 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y8X8 | ColorDataType.Integer, - I1 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X1 | ColorDataType.Integer, - I2 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X2 | ColorDataType.Integer, - I4 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X4 | ColorDataType.Integer, - I8 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - A8Y8U8V8 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16Y16U16V16 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Y8U8V8A8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - V8_U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - YVYU = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, - VYUY = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, - UYVY = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, - YUYV = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, - Y8_U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - V8_U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - U8_V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - Y8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - V8_U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - U8_V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - Y8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - V8_U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - V8_U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - V10U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U10V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - Bayer8RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - XYZ = ColorSpace.XYZ | ColorSwizzle.XYZ1 | ColorComponent.X20Y20Z20 | ColorDataType.Float, - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/Display.cs b/Ryujinx.HLE/HOS/Services/Vi/Display.cs deleted file mode 100644 index 47c7b2ae..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/Display.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class Display - { - public string Name { get; private set; } - - public Display(string name) - { - Name = name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs b/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs deleted file mode 100644 index 75b543b8..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs +++ /dev/null @@ -1,165 +0,0 @@ -using Ryujinx.Common; -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Android -{ - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - struct GraphicBufferHeader - { - public int Magic; - public int Width; - public int Height; - public int Stride; - public int Format; - public int Usage; - - public int Pid; - public int RefCount; - - public int FdsCount; - public int IntsCount; - } - - [StructLayout(LayoutKind.Explicit, Size = 0x58)] - struct NvGraphicBufferSurface - { - [FieldOffset(0)] - public uint Width; - - [FieldOffset(0x4)] - public uint Height; - - [FieldOffset(0x8)] - public ColorFormat ColorFormat; - - [FieldOffset(0x10)] - public int Layout; - - [FieldOffset(0x14)] - public int Pitch; - - [FieldOffset(0x18)] - public int NvMapHandle; - - [FieldOffset(0x1C)] - public int Offset; - - [FieldOffset(0x20)] - public int Kind; - - [FieldOffset(0x24)] - public int BlockHeightLog2; - - [FieldOffset(0x28)] - public int ScanFormat; - - [FieldOffset(0x30)] - public long Flags; - - [FieldOffset(0x38)] - public long Size; - } - - [StructLayout(LayoutKind.Explicit)] - struct NvGraphicBufferSurfaceArray - { - [FieldOffset(0x0)] - private NvGraphicBufferSurface Surface0; - - [FieldOffset(0x58)] - private NvGraphicBufferSurface Surface1; - - [FieldOffset(0xb0)] - private NvGraphicBufferSurface Surface2; - - public NvGraphicBufferSurface this[int index] - { - get - { - if (index == 0) - { - return Surface0; - } - else if (index == 1) - { - return Surface1; - } - else if (index == 2) - { - return Surface2; - } - - throw new IndexOutOfRangeException(); - } - } - } - - [StructLayout(LayoutKind.Explicit, Size = 0x144)] - struct NvGraphicBuffer - { - [FieldOffset(0x4)] - public int NvMapId; - - [FieldOffset(0xC)] - public int Magic; - - [FieldOffset(0x10)] - public int Pid; - - [FieldOffset(0x14)] - public int Type; - - [FieldOffset(0x18)] - public int Usage; - - [FieldOffset(0x1C)] - public int PixelFormat; - - [FieldOffset(0x20)] - public int ExternalPixelFormat; - - [FieldOffset(0x24)] - public int Stride; - - [FieldOffset(0x28)] - public int FrameBufferSize; - - [FieldOffset(0x2C)] - public int PlanesCount; - - [FieldOffset(0x34)] - public NvGraphicBufferSurfaceArray Surfaces; - } - - struct GbpBuffer - { - public GraphicBufferHeader Header { get; private set; } - public NvGraphicBuffer Buffer { get; private set; } - - public int Size => Marshal.SizeOf() + Marshal.SizeOf(); - - public GbpBuffer(BinaryReader reader) - { - Header = reader.ReadStruct(); - - // ignore fds - // TODO: check if that is used in official implementation - reader.BaseStream.Position += Header.FdsCount * 4; - - if (Header.IntsCount != 0x51) - { - throw new NotImplementedException($"Unexpected Graphic Buffer ints count (expected 0x51, found 0x{Header.IntsCount:x}"); - } - - Buffer = reader.ReadStruct(); - } - - public void Write(BinaryWriter writer) - { - writer.WriteStruct(Header); - writer.WriteStruct(Buffer); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs deleted file mode 100644 index 15db6ff2..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs +++ /dev/null @@ -1,287 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using System; -using System.IO; -using System.Text; - -using static Ryujinx.HLE.HOS.Services.Android.Parcel; - -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class IApplicationDisplayService : IpcService - { - private IdDictionary _displays; - - public IApplicationDisplayService() - { - _displays = new IdDictionary(); - } - - [Command(100)] - // GetRelayService() -> object - public ResultCode GetRelayService(ServiceCtx context) - { - MakeObject(context, new IHOSBinderDriver( - context.Device.System, - context.Device.Gpu.Renderer)); - - return ResultCode.Success; - } - - [Command(101)] - // GetSystemDisplayService() -> object - public ResultCode GetSystemDisplayService(ServiceCtx context) - { - MakeObject(context, new ISystemDisplayService(this)); - - return ResultCode.Success; - } - - [Command(102)] - // GetManagerDisplayService() -> object - public ResultCode GetManagerDisplayService(ServiceCtx context) - { - MakeObject(context, new IManagerDisplayService(this)); - - return ResultCode.Success; - } - - [Command(103)] // 2.0.0+ - // GetIndirectDisplayTransactionService() -> object - public ResultCode GetIndirectDisplayTransactionService(ServiceCtx context) - { - MakeObject(context, new IHOSBinderDriver( - context.Device.System, - context.Device.Gpu.Renderer)); - - return ResultCode.Success; - } - - [Command(1000)] - // ListDisplays() -> (u64, buffer) - public ResultCode ListDisplays(ServiceCtx context) - { - long recBuffPtr = context.Request.ReceiveBuff[0].Position; - - MemoryHelper.FillWithZeros(context.Memory, recBuffPtr, 0x60); - - // Add only the default display to buffer - context.Memory.WriteBytes(recBuffPtr, Encoding.ASCII.GetBytes("Default")); - context.Memory.WriteInt64(recBuffPtr + 0x40, 0x1L); - context.Memory.WriteInt64(recBuffPtr + 0x48, 0x1L); - context.Memory.WriteInt64(recBuffPtr + 0x50, 1920L); - context.Memory.WriteInt64(recBuffPtr + 0x58, 1080L); - - context.ResponseData.Write(1L); - - return ResultCode.Success; - } - - [Command(1010)] - // OpenDisplay(nn::vi::DisplayName) -> u64 - public ResultCode OpenDisplay(ServiceCtx context) - { - string name = GetDisplayName(context); - - long displayId = _displays.Add(new Display(name)); - - context.ResponseData.Write(displayId); - - return ResultCode.Success; - } - - [Command(1020)] - // CloseDisplay(u64) - public ResultCode CloseDisplay(ServiceCtx context) - { - int displayId = context.RequestData.ReadInt32(); - - _displays.Delete(displayId); - - return ResultCode.Success; - } - - [Command(1102)] - // GetDisplayResolution(u64) -> (u64, u64) - public ResultCode GetDisplayResolution(ServiceCtx context) - { - long displayId = context.RequestData.ReadInt32(); - - context.ResponseData.Write(1280); - context.ResponseData.Write(720); - - return ResultCode.Success; - } - - [Command(2020)] - // OpenLayer(nn::vi::DisplayName, u64, nn::applet::AppletResourceUserId, pid) -> (u64, buffer) - public ResultCode OpenLayer(ServiceCtx context) - { - long layerId = context.RequestData.ReadInt64(); - long userId = context.RequestData.ReadInt64(); - - long parcelPtr = context.Request.ReceiveBuff[0].Position; - - byte[] parcel = MakeIGraphicsBufferProducer(parcelPtr); - - context.Memory.WriteBytes(parcelPtr, parcel); - - context.ResponseData.Write((long)parcel.Length); - - return ResultCode.Success; - } - - [Command(2021)] - // CloseLayer(u64) - public ResultCode CloseLayer(ServiceCtx context) - { - long layerId = context.RequestData.ReadInt64(); - - return ResultCode.Success; - } - - [Command(2030)] - // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) - public ResultCode CreateStrayLayer(ServiceCtx context) - { - long layerFlags = context.RequestData.ReadInt64(); - long displayId = context.RequestData.ReadInt64(); - - long parcelPtr = context.Request.ReceiveBuff[0].Position; - - Display disp = _displays.GetData((int)displayId); - - byte[] parcel = MakeIGraphicsBufferProducer(parcelPtr); - - context.Memory.WriteBytes(parcelPtr, parcel); - - context.ResponseData.Write(0L); - context.ResponseData.Write((long)parcel.Length); - - return ResultCode.Success; - } - - [Command(2031)] - // DestroyStrayLayer(u64) - public ResultCode DestroyStrayLayer(ServiceCtx context) - { - return ResultCode.Success; - } - - [Command(2101)] - // SetLayerScalingMode(u32, u64) - public ResultCode SetLayerScalingMode(ServiceCtx context) - { - int scalingMode = context.RequestData.ReadInt32(); - long unknown = context.RequestData.ReadInt64(); - - return ResultCode.Success; - } - - [Command(2102)] // 5.0.0+ - // ConvertScalingMode(unknown) -> unknown - public ResultCode ConvertScalingMode(ServiceCtx context) - { - SrcScalingMode scalingMode = (SrcScalingMode)context.RequestData.ReadInt32(); - - DstScalingMode? convertedScalingMode = ConvertScalingMode(scalingMode); - - if (!convertedScalingMode.HasValue) - { - // Scaling mode out of the range of valid values. - return ResultCode.InvalidArguments; - } - - if (scalingMode != SrcScalingMode.ScaleToWindow && - scalingMode != SrcScalingMode.PreserveAspectRatio) - { - // Invalid scaling mode specified. - return ResultCode.InvalidScalingMode; - } - - context.ResponseData.Write((ulong)convertedScalingMode); - - return ResultCode.Success; - } - - private DstScalingMode? ConvertScalingMode(SrcScalingMode source) - { - switch (source) - { - case SrcScalingMode.None: return DstScalingMode.None; - case SrcScalingMode.Freeze: return DstScalingMode.Freeze; - case SrcScalingMode.ScaleAndCrop: return DstScalingMode.ScaleAndCrop; - case SrcScalingMode.ScaleToWindow: return DstScalingMode.ScaleToWindow; - case SrcScalingMode.PreserveAspectRatio: return DstScalingMode.PreserveAspectRatio; - } - - return null; - } - - [Command(5202)] - // GetDisplayVsyncEvent(u64) -> handle - public ResultCode GetDisplayVSyncEvent(ServiceCtx context) - { - string name = GetDisplayName(context); - - if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - return ResultCode.Success; - } - - private byte[] MakeIGraphicsBufferProducer(long basePtr) - { - long id = 0x20; - long cookiePtr = 0L; - - using (MemoryStream ms = new MemoryStream()) - { - BinaryWriter writer = new BinaryWriter(ms); - - // flat_binder_object (size is 0x28) - writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) - writer.Write(0); //Flags - writer.Write((int)(id >> 0)); - writer.Write((int)(id >> 32)); - writer.Write((int)(cookiePtr >> 0)); - writer.Write((int)(cookiePtr >> 32)); - writer.Write((byte)'d'); - writer.Write((byte)'i'); - writer.Write((byte)'s'); - writer.Write((byte)'p'); - writer.Write((byte)'d'); - writer.Write((byte)'r'); - writer.Write((byte)'v'); - writer.Write((byte)'\0'); - writer.Write(0L); //Pad - - return MakeParcel(ms.ToArray(), new byte[] { 0, 0, 0, 0 }); - } - } - - private string GetDisplayName(ServiceCtx context) - { - string name = string.Empty; - - for (int index = 0; index < 8 && - context.RequestData.BaseStream.Position < - context.RequestData.BaseStream.Length; index++) - { - byte chr = context.RequestData.ReadByte(); - - if (chr >= 0x20 && chr < 0x7f) - { - name += (char)chr; - } - } - - return name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs index e0f71d0f..dbadd90b 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Vi.RootService; + namespace Ryujinx.HLE.HOS.Services.Vi { [Service("vi:u")] diff --git a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs deleted file mode 100644 index 4da0e2ff..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Android; -using System; - -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class IHOSBinderDriver : IpcService, IDisposable - { - private KEvent _binderEvent; - - private NvFlinger _flinger; - - public IHOSBinderDriver(Horizon system, IGalRenderer renderer) - { - _binderEvent = new KEvent(system); - - _binderEvent.ReadableEvent.Signal(); - - _flinger = new NvFlinger(renderer, _binderEvent); - } - - [Command(0)] - // TransactParcel(s32, u32, u32, buffer) -> buffer - public ResultCode TransactParcel(ServiceCtx context) - { - int id = context.RequestData.ReadInt32(); - int code = context.RequestData.ReadInt32(); - - long dataPos = context.Request.SendBuff[0].Position; - long dataSize = context.Request.SendBuff[0].Size; - - byte[] data = context.Memory.ReadBytes(dataPos, dataSize); - - data = Parcel.GetParcelData(data); - - return (ResultCode)_flinger.ProcessParcelRequest(context, data, code); - } - - [Command(1)] - // AdjustRefcount(s32, s32, s32) - public ResultCode AdjustRefcount(ServiceCtx context) - { - int id = context.RequestData.ReadInt32(); - int addVal = context.RequestData.ReadInt32(); - int type = context.RequestData.ReadInt32(); - - return ResultCode.Success; - } - - [Command(2)] - // GetNativeHandle(s32, s32) -> handle - public ResultCode GetNativeHandle(ServiceCtx context) - { - int id = context.RequestData.ReadInt32(); - uint unk = context.RequestData.ReadUInt32(); - - if (context.Process.HandleTable.GenerateHandle(_binderEvent.ReadableEvent, out int handle) != KernelResult.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle); - - return ResultCode.Success; - } - - [Command(3)] // 3.0.0+ - // TransactParcelAuto(s32, u32, u32, buffer) -> buffer - public ResultCode TransactParcelAuto(ServiceCtx context) - { - int id = context.RequestData.ReadInt32(); - int code = context.RequestData.ReadInt32(); - - (long dataPos, long dataSize) = context.Request.GetBufferType0x21(); - - byte[] data = context.Memory.ReadBytes(dataPos, dataSize); - - data = Parcel.GetParcelData(data); - - return (ResultCode)_flinger.ProcessParcelRequest(context, data, code); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _flinger.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs deleted file mode 100644 index 3a64be15..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class IManagerDisplayService : IpcService - { - private static IApplicationDisplayService _applicationDisplayService; - - public IManagerDisplayService(IApplicationDisplayService applicationDisplayService) - { - _applicationDisplayService = applicationDisplayService; - } - - [Command(2010)] - // CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64 - public ResultCode CreateManagedLayer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - context.ResponseData.Write(0L); //LayerId - - return ResultCode.Success; - } - - [Command(2011)] - // DestroyManagedLayer(u64) - public ResultCode DestroyManagedLayer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return ResultCode.Success; - } - - [Command(2012)] // 7.0.0+ - // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) - public ResultCode CreateStrayLayer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return _applicationDisplayService.CreateStrayLayer(context); - } - - [Command(6000)] - // AddToLayerStack(u32, u64) - public ResultCode AddToLayerStack(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return ResultCode.Success; - } - - [Command(6002)] - // SetLayerVisibility(b8, u64) - public ResultCode SetLayerVisibility(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs index feaf4612..31996ff1 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Vi.RootService; + namespace Ryujinx.HLE.HOS.Services.Vi { [Service("vi:m")] diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs deleted file mode 100644 index dc0430f6..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Ryujinx.Common.Logging; - -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class ISystemDisplayService : IpcService - { - private static IApplicationDisplayService _applicationDisplayService; - - public ISystemDisplayService(IApplicationDisplayService applicationDisplayService) - { - _applicationDisplayService = applicationDisplayService; - } - - [Command(2205)] - // SetLayerZ(u64, u64) - public ResultCode SetLayerZ(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return ResultCode.Success; - } - - [Command(2207)] - // SetLayerVisibility(b8, u64) - public ResultCode SetLayerVisibility(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return ResultCode.Success; - } - - [Command(2312)] // 1.0.0-6.2.0 - // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) - public ResultCode CreateStrayLayer(ServiceCtx context) - { - Logger.PrintStub(LogClass.ServiceVi); - - return _applicationDisplayService.CreateStrayLayer(context); - } - - [Command(3200)] - // GetDisplayMode(u64) -> nn::vi::DisplayModeInfo - public ResultCode GetDisplayMode(ServiceCtx context) - { - // TODO: De-hardcode resolution. - context.ResponseData.Write(1280); - context.ResponseData.Write(720); - context.ResponseData.Write(60.0f); - context.ResponseData.Write(0); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs index 09d604c1..8d64e475 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Vi.RootService; + namespace Ryujinx.HLE.HOS.Services.Vi { [Service("vi:s")] diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs deleted file mode 100644 index 5db028cc..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs +++ /dev/null @@ -1,508 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; -using Ryujinx.HLE.HOS.Services.Nv.NvMap; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; - -using static Ryujinx.HLE.HOS.Services.Android.Parcel; - -namespace Ryujinx.HLE.HOS.Services.Android -{ - class NvFlinger : IDisposable - { - private delegate ResultCode ServiceProcessParcel(ServiceCtx context, BinaryReader parcelReader); - - private Dictionary<(string, int), ServiceProcessParcel> _commands; - - private KEvent _binderEvent; - - private IGalRenderer _renderer; - - private const int BufferQueueCount = 0x40; - private const int BufferQueueMask = BufferQueueCount - 1; - - [Flags] - private enum HalTransform - { - FlipX = 1, - FlipY = 2, - Rotate90 = 4, - Rotate180 = FlipX | FlipY, - Rotate270 = Rotate90 | Rotate180, - } - - private enum BufferState - { - Free, - Dequeued, - Queued, - Acquired - } - - [StructLayout(LayoutKind.Sequential, Size = 0x8)] - private struct Fence - { - public int id; - public int value; - } - - [StructLayout(LayoutKind.Explicit, Size = 0x24)] - private struct MultiFence - { - [FieldOffset(0x0)] - public int FenceCount; - - [FieldOffset(0x4)] - public Fence Fence0; - - [FieldOffset(0xC)] - public Fence Fence1; - - [FieldOffset(0x14)] - public Fence Fence2; - - [FieldOffset(0x1C)] - public Fence Fence3; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - private struct Rect - { - public int Top; - public int Left; - public int Right; - public int Bottom; - } - - [StructLayout(LayoutKind.Explicit)] - private struct QueueBufferObject - { - [FieldOffset(0x0)] - public long Timestamp; - - [FieldOffset(0x8)] - public int IsAutoTimestamp; - - [FieldOffset(0xC)] - public Rect Crop; - - [FieldOffset(0x1C)] - public int ScalingMode; - - [FieldOffset(0x20)] - public HalTransform Transform; - - [FieldOffset(0x24)] - public int StickyTransform; - - [FieldOffset(0x28)] - public int Unknown; - - [FieldOffset(0x2C)] - public int SwapInterval; - - [FieldOffset(0x30)] - public MultiFence Fence; - } - - private struct BufferEntry - { - public BufferState State; - - public HalTransform Transform; - - public Rect Crop; - - public GbpBuffer Data; - } - - private BufferEntry[] _bufferQueue; - - private AutoResetEvent _waitBufferFree; - - private bool _disposed; - - public NvFlinger(IGalRenderer renderer, KEvent binderEvent) - { - _commands = new Dictionary<(string, int), ServiceProcessParcel> - { - { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, - { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, - { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, - { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } - }; - - _renderer = renderer; - _binderEvent = binderEvent; - - _bufferQueue = new BufferEntry[0x40]; - - _waitBufferFree = new AutoResetEvent(false); - } - - public ResultCode ProcessParcelRequest(ServiceCtx context, byte[] parcelData, int code) - { - using (MemoryStream ms = new MemoryStream(parcelData)) - { - BinaryReader reader = new BinaryReader(ms); - - ms.Seek(4, SeekOrigin.Current); - - int strSize = reader.ReadInt32(); - - string interfaceName = Encoding.Unicode.GetString(reader.ReadBytes(strSize * 2)); - - long remainder = ms.Position & 0xf; - - if (remainder != 0) - { - ms.Seek(0x10 - remainder, SeekOrigin.Current); - } - - ms.Seek(0x50, SeekOrigin.Begin); - - if (_commands.TryGetValue((interfaceName, code), out ServiceProcessParcel procReq)) - { - Logger.PrintDebug(LogClass.ServiceVi, $"{interfaceName} {procReq.Method.Name}"); - - return procReq(context, reader); - } - else - { - throw new NotImplementedException($"{interfaceName} {code}"); - } - } - } - - private ResultCode GbpRequestBuffer(ServiceCtx context, BinaryReader parcelReader) - { - int slot = parcelReader.ReadInt32(); - - using (MemoryStream ms = new MemoryStream()) - { - BinaryWriter writer = new BinaryWriter(ms); - - BufferEntry entry = _bufferQueue[slot]; - - int bufferCount = 1; //? - long bufferSize = entry.Data.Size; - - writer.Write(bufferCount); - writer.Write(bufferSize); - - entry.Data.Write(writer); - - writer.Write(0); - - return MakeReplyParcel(context, ms.ToArray()); - } - } - - private ResultCode GbpDequeueBuffer(ServiceCtx context, BinaryReader parcelReader) - { - // TODO: Errors. - int format = parcelReader.ReadInt32(); - int width = parcelReader.ReadInt32(); - int height = parcelReader.ReadInt32(); - int getTimestamps = parcelReader.ReadInt32(); - int usage = parcelReader.ReadInt32(); - - int slot = GetFreeSlotBlocking(width, height); - - return MakeReplyParcel(context, slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - - private ResultCode GbpQueueBuffer(ServiceCtx context, BinaryReader parcelReader) - { - context.Device.Statistics.RecordGameFrameTime(); - - // TODO: Errors. - int slot = parcelReader.ReadInt32(); - - long Position = parcelReader.BaseStream.Position; - - QueueBufferObject queueBufferObject = ReadFlattenedObject(parcelReader); - - parcelReader.BaseStream.Position = Position; - - _bufferQueue[slot].Transform = queueBufferObject.Transform; - _bufferQueue[slot].Crop = queueBufferObject.Crop; - - _bufferQueue[slot].State = BufferState.Queued; - - SendFrameBuffer(context, slot); - - if (context.Device.EnableDeviceVsync) - { - context.Device.VsyncEvent.WaitOne(); - } - - return MakeReplyParcel(context, 1280, 720, 0, 0, 0); - } - - private ResultCode GbpDetachBuffer(ServiceCtx context, BinaryReader parcelReader) - { - return MakeReplyParcel(context, 0); - } - - private ResultCode GbpCancelBuffer(ServiceCtx context, BinaryReader parcelReader) - { - // TODO: Errors. - int slot = parcelReader.ReadInt32(); - - MultiFence fence = ReadFlattenedObject(parcelReader); - - _bufferQueue[slot].State = BufferState.Free; - - _waitBufferFree.Set(); - - return MakeReplyParcel(context, 0); - } - - private ResultCode GbpQuery(ServiceCtx context, BinaryReader parcelReader) - { - return MakeReplyParcel(context, 0, 0); - } - - private ResultCode GbpConnect(ServiceCtx context, BinaryReader parcelReader) - { - return MakeReplyParcel(context, 1280, 720, 0, 0, 0); - } - - private ResultCode GbpDisconnect(ServiceCtx context, BinaryReader parcelReader) - { - return MakeReplyParcel(context, 0); - } - - private ResultCode GbpPreallocBuffer(ServiceCtx context, BinaryReader parcelReader) - { - int slot = parcelReader.ReadInt32(); - - bool hasInput = parcelReader.ReadInt32() == 1; - - if (hasInput) - { - byte[] graphicBuffer = ReadFlattenedObject(parcelReader); - - _bufferQueue[slot].State = BufferState.Free; - - using (BinaryReader graphicBufferReader = new BinaryReader(new MemoryStream(graphicBuffer))) - { - _bufferQueue[slot].Data = new GbpBuffer(graphicBufferReader); - } - - } - - return MakeReplyParcel(context, 0); - } - - private byte[] ReadFlattenedObject(BinaryReader reader) - { - long flattenedObjectSize = reader.ReadInt64(); - - return reader.ReadBytes((int)flattenedObjectSize); - } - - private unsafe T ReadFlattenedObject(BinaryReader reader) where T: struct - { - byte[] data = ReadFlattenedObject(reader); - - fixed (byte* ptr = data) - { - return Marshal.PtrToStructure((IntPtr)ptr); - } - } - - private ResultCode MakeReplyParcel(ServiceCtx context, params int[] ints) - { - using (MemoryStream ms = new MemoryStream()) - { - BinaryWriter writer = new BinaryWriter(ms); - - foreach (int Int in ints) - { - writer.Write(Int); - } - - return MakeReplyParcel(context, ms.ToArray()); - } - } - - private ResultCode MakeReplyParcel(ServiceCtx context, byte[] data) - { - (long replyPos, long replySize) = context.Request.GetBufferType0x22(); - - byte[] reply = MakeParcel(data, new byte[0]); - - context.Memory.WriteBytes(replyPos, reply); - - return ResultCode.Success; - } - - private GalImageFormat ConvertColorFormat(ColorFormat colorFormat) - { - switch (colorFormat) - { - case ColorFormat.A8B8G8R8: - return GalImageFormat.Rgba8 | GalImageFormat.Unorm; - case ColorFormat.X8B8G8R8: - return GalImageFormat.Rgbx8 | GalImageFormat.Unorm; - case ColorFormat.R5G6B5: - return GalImageFormat.Bgr565 | GalImageFormat.Unorm; - case ColorFormat.A8R8G8B8: - return GalImageFormat.Bgra8 | GalImageFormat.Unorm; - case ColorFormat.A4B4G4R4: - return GalImageFormat.Rgba4 | GalImageFormat.Unorm; - default: - throw new NotImplementedException($"Color Format \"{colorFormat}\" not implemented!"); - } - } - - // TODO: support multi surface - private void SendFrameBuffer(ServiceCtx context, int slot) - { - int fbWidth = _bufferQueue[slot].Data.Header.Width; - int fbHeight = _bufferQueue[slot].Data.Header.Height; - - int nvMapHandle = _bufferQueue[slot].Data.Buffer.Surfaces[0].NvMapHandle; - - if (nvMapHandle == 0) - { - nvMapHandle = _bufferQueue[slot].Data.Buffer.NvMapId; - } - - int bufferOffset = _bufferQueue[slot].Data.Buffer.Surfaces[0].Offset; - - NvMapHandle map = NvMapIoctl.GetNvMap(context, nvMapHandle); - - long fbAddr = map.Address + bufferOffset; - - _bufferQueue[slot].State = BufferState.Acquired; - - Rect crop = _bufferQueue[slot].Crop; - - bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX); - bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY); - - GalImageFormat imageFormat = ConvertColorFormat(_bufferQueue[slot].Data.Buffer.Surfaces[0].ColorFormat); - - int BlockHeight = 1 << _bufferQueue[slot].Data.Buffer.Surfaces[0].BlockHeightLog2; - - // Note: Rotation is being ignored. - - int top = crop.Top; - int left = crop.Left; - int right = crop.Right; - int bottom = crop.Bottom; - - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; - - _renderer.QueueAction(() => - { - if (!_renderer.Texture.TryGetImage(fbAddr, out GalImage image)) - { - image = new GalImage( - fbWidth, - fbHeight, 1, 1, 1, BlockHeight, 1, - GalMemoryLayout.BlockLinear, - imageFormat, - GalTextureTarget.TwoD); - } - - context.Device.Gpu.ResourceManager.ClearPbCache(); - context.Device.Gpu.ResourceManager.SendTexture(vmm, fbAddr, image); - - _renderer.RenderTarget.SetTransform(flipX, flipY, top, left, right, bottom); - _renderer.RenderTarget.Present(fbAddr); - - ReleaseBuffer(slot); - }); - } - - private void ReleaseBuffer(int slot) - { - _bufferQueue[slot].State = BufferState.Free; - - _binderEvent.ReadableEvent.Signal(); - - _waitBufferFree.Set(); - } - - private int GetFreeSlotBlocking(int width, int height) - { - int slot; - - do - { - if ((slot = GetFreeSlot(width, height)) != -1) - { - break; - } - - if (_disposed) - { - break; - } - - _waitBufferFree.WaitOne(); - } - while (!_disposed); - - return slot; - } - - private int GetFreeSlot(int width, int height) - { - lock (_bufferQueue) - { - for (int slot = 0; slot < _bufferQueue.Length; slot++) - { - if (_bufferQueue[slot].State != BufferState.Free) - { - continue; - } - - GbpBuffer data = _bufferQueue[slot].Data; - - if (data.Header.Width == width && - data.Header.Height == height) - { - _bufferQueue[slot].State = BufferState.Dequeued; - - return slot; - } - } - } - - return -1; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing && !_disposed) - { - _disposed = true; - - _waitBufferFree.Set(); - _waitBufferFree.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs b/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs deleted file mode 100644 index 63c5a82f..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.HLE.HOS.Services.Android -{ - static class Parcel - { - public static byte[] GetParcelData(byte[] parcel) - { - if (parcel == null) - { - throw new ArgumentNullException(nameof(parcel)); - } - - using (MemoryStream ms = new MemoryStream(parcel)) - { - BinaryReader reader = new BinaryReader(ms); - - int dataSize = reader.ReadInt32(); - int dataOffset = reader.ReadInt32(); - int objsSize = reader.ReadInt32(); - int objsOffset = reader.ReadInt32(); - - ms.Seek(dataOffset - 0x10, SeekOrigin.Current); - - return reader.ReadBytes(dataSize); - } - } - - public static byte[] MakeParcel(byte[] data, byte[] objs) - { - if (data == null) - { - throw new ArgumentNullException(nameof(data)); - } - - if (objs == null) - { - throw new ArgumentNullException(nameof(objs)); - } - - using (MemoryStream ms = new MemoryStream()) - { - BinaryWriter writer = new BinaryWriter(ms); - - writer.Write(data.Length); - writer.Write(0x10); - writer.Write(objs.Length); - writer.Write(data.Length + 0x10); - - writer.Write(data); - writer.Write(objs); - - return ms.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs new file mode 100644 index 00000000..47c7b2ae --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class Display + { + public string Name { get; private set; } + + public Display(string name) + { + Name = name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IHOSBinderDriver.cs new file mode 100644 index 00000000..3ac1c270 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IHOSBinderDriver.cs @@ -0,0 +1,99 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Android; +using System; + +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + class IHOSBinderDriver : IpcService, IDisposable + { + private KEvent _binderEvent; + + private NvFlinger _flinger; + + public IHOSBinderDriver(Horizon system, IGalRenderer renderer) + { + _binderEvent = new KEvent(system); + + _binderEvent.ReadableEvent.Signal(); + + _flinger = new NvFlinger(renderer, _binderEvent); + } + + [Command(0)] + // TransactParcel(s32, u32, u32, buffer) -> buffer + public ResultCode TransactParcel(ServiceCtx context) + { + int id = context.RequestData.ReadInt32(); + int code = context.RequestData.ReadInt32(); + + long dataPos = context.Request.SendBuff[0].Position; + long dataSize = context.Request.SendBuff[0].Size; + + byte[] data = context.Memory.ReadBytes(dataPos, dataSize); + + data = Parcel.GetParcelData(data); + + return (ResultCode)_flinger.ProcessParcelRequest(context, data, code); + } + + [Command(1)] + // AdjustRefcount(s32, s32, s32) + public ResultCode AdjustRefcount(ServiceCtx context) + { + int id = context.RequestData.ReadInt32(); + int addVal = context.RequestData.ReadInt32(); + int type = context.RequestData.ReadInt32(); + + return ResultCode.Success; + } + + [Command(2)] + // GetNativeHandle(s32, s32) -> handle + public ResultCode GetNativeHandle(ServiceCtx context) + { + int id = context.RequestData.ReadInt32(); + uint unk = context.RequestData.ReadUInt32(); + + if (context.Process.HandleTable.GenerateHandle(_binderEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle); + + return ResultCode.Success; + } + + [Command(3)] // 3.0.0+ + // TransactParcelAuto(s32, u32, u32, buffer) -> buffer + public ResultCode TransactParcelAuto(ServiceCtx context) + { + int id = context.RequestData.ReadInt32(); + int code = context.RequestData.ReadInt32(); + + (long dataPos, long dataSize) = context.Request.GetBufferType0x21(); + + byte[] data = context.Memory.ReadBytes(dataPos, dataSize); + + data = Parcel.GetParcelData(data); + + return (ResultCode)_flinger.ProcessParcelRequest(context, data, code); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _flinger.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs new file mode 100644 index 00000000..24e73244 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs @@ -0,0 +1,61 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + class IManagerDisplayService : IpcService + { + private static IApplicationDisplayService _applicationDisplayService; + + public IManagerDisplayService(IApplicationDisplayService applicationDisplayService) + { + _applicationDisplayService = applicationDisplayService; + } + + [Command(2010)] + // CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64 + public ResultCode CreateManagedLayer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + context.ResponseData.Write(0L); //LayerId + + return ResultCode.Success; + } + + [Command(2011)] + // DestroyManagedLayer(u64) + public ResultCode DestroyManagedLayer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return ResultCode.Success; + } + + [Command(2012)] // 7.0.0+ + // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) + public ResultCode CreateStrayLayer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return _applicationDisplayService.CreateStrayLayer(context); + } + + [Command(6000)] + // AddToLayerStack(u32, u64) + public ResultCode AddToLayerStack(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return ResultCode.Success; + } + + [Command(6002)] + // SetLayerVisibility(b8, u64) + public ResultCode SetLayerVisibility(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs new file mode 100644 index 00000000..1e615bd2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs @@ -0,0 +1,54 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + class ISystemDisplayService : IpcService + { + private static IApplicationDisplayService _applicationDisplayService; + + public ISystemDisplayService(IApplicationDisplayService applicationDisplayService) + { + _applicationDisplayService = applicationDisplayService; + } + + [Command(2205)] + // SetLayerZ(u64, u64) + public ResultCode SetLayerZ(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return ResultCode.Success; + } + + [Command(2207)] + // SetLayerVisibility(b8, u64) + public ResultCode SetLayerVisibility(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return ResultCode.Success; + } + + [Command(2312)] // 1.0.0-6.2.0 + // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) + public ResultCode CreateStrayLayer(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceVi); + + return _applicationDisplayService.CreateStrayLayer(context); + } + + [Command(3200)] + // GetDisplayMode(u64) -> nn::vi::DisplayModeInfo + public ResultCode GetDisplayMode(ServiceCtx context) + { + // TODO: De-hardcode resolution. + context.ResponseData.Write(1280); + context.ResponseData.Write(720); + context.ResponseData.Write(60.0f); + context.ResponseData.Write(0); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DestinationScalingMode.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DestinationScalingMode.cs new file mode 100644 index 00000000..cf459cb2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DestinationScalingMode.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + enum DestinationScalingMode + { + Freeze, + ScaleToWindow, + ScaleAndCrop, + None, + PreserveAspectRatio + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/SourceScalingMode.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/SourceScalingMode.cs new file mode 100644 index 00000000..ac8c3e02 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/SourceScalingMode.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + enum SourceScalingMode + { + None, + Freeze, + ScaleToWindow, + ScaleAndCrop, + PreserveAspectRatio + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs new file mode 100644 index 00000000..fba25054 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -0,0 +1,288 @@ +using ARMeilleure.Memory; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; +using System; +using System.IO; +using System.Text; + +using static Ryujinx.HLE.HOS.Services.Android.Parcel; + +namespace Ryujinx.HLE.HOS.Services.Vi.RootService +{ + class IApplicationDisplayService : IpcService + { + private IdDictionary _displays; + + public IApplicationDisplayService() + { + _displays = new IdDictionary(); + } + + [Command(100)] + // GetRelayService() -> object + public ResultCode GetRelayService(ServiceCtx context) + { + MakeObject(context, new IHOSBinderDriver( + context.Device.System, + context.Device.Gpu.Renderer)); + + return ResultCode.Success; + } + + [Command(101)] + // GetSystemDisplayService() -> object + public ResultCode GetSystemDisplayService(ServiceCtx context) + { + MakeObject(context, new ISystemDisplayService(this)); + + return ResultCode.Success; + } + + [Command(102)] + // GetManagerDisplayService() -> object + public ResultCode GetManagerDisplayService(ServiceCtx context) + { + MakeObject(context, new IManagerDisplayService(this)); + + return ResultCode.Success; + } + + [Command(103)] // 2.0.0+ + // GetIndirectDisplayTransactionService() -> object + public ResultCode GetIndirectDisplayTransactionService(ServiceCtx context) + { + MakeObject(context, new IHOSBinderDriver( + context.Device.System, + context.Device.Gpu.Renderer)); + + return ResultCode.Success; + } + + [Command(1000)] + // ListDisplays() -> (u64, buffer) + public ResultCode ListDisplays(ServiceCtx context) + { + long recBuffPtr = context.Request.ReceiveBuff[0].Position; + + MemoryHelper.FillWithZeros(context.Memory, recBuffPtr, 0x60); + + // Add only the default display to buffer + context.Memory.WriteBytes(recBuffPtr, Encoding.ASCII.GetBytes("Default")); + context.Memory.WriteInt64(recBuffPtr + 0x40, 0x1L); + context.Memory.WriteInt64(recBuffPtr + 0x48, 0x1L); + context.Memory.WriteInt64(recBuffPtr + 0x50, 1920L); + context.Memory.WriteInt64(recBuffPtr + 0x58, 1080L); + + context.ResponseData.Write(1L); + + return ResultCode.Success; + } + + [Command(1010)] + // OpenDisplay(nn::vi::DisplayName) -> u64 + public ResultCode OpenDisplay(ServiceCtx context) + { + string name = GetDisplayName(context); + + long displayId = _displays.Add(new Display(name)); + + context.ResponseData.Write(displayId); + + return ResultCode.Success; + } + + [Command(1020)] + // CloseDisplay(u64) + public ResultCode CloseDisplay(ServiceCtx context) + { + int displayId = context.RequestData.ReadInt32(); + + _displays.Delete(displayId); + + return ResultCode.Success; + } + + [Command(1102)] + // GetDisplayResolution(u64) -> (u64, u64) + public ResultCode GetDisplayResolution(ServiceCtx context) + { + long displayId = context.RequestData.ReadInt32(); + + context.ResponseData.Write(1280); + context.ResponseData.Write(720); + + return ResultCode.Success; + } + + [Command(2020)] + // OpenLayer(nn::vi::DisplayName, u64, nn::applet::AppletResourceUserId, pid) -> (u64, buffer) + public ResultCode OpenLayer(ServiceCtx context) + { + long layerId = context.RequestData.ReadInt64(); + long userId = context.RequestData.ReadInt64(); + + long parcelPtr = context.Request.ReceiveBuff[0].Position; + + byte[] parcel = MakeIGraphicsBufferProducer(parcelPtr); + + context.Memory.WriteBytes(parcelPtr, parcel); + + context.ResponseData.Write((long)parcel.Length); + + return ResultCode.Success; + } + + [Command(2021)] + // CloseLayer(u64) + public ResultCode CloseLayer(ServiceCtx context) + { + long layerId = context.RequestData.ReadInt64(); + + return ResultCode.Success; + } + + [Command(2030)] + // CreateStrayLayer(u32, u64) -> (u64, u64, buffer) + public ResultCode CreateStrayLayer(ServiceCtx context) + { + long layerFlags = context.RequestData.ReadInt64(); + long displayId = context.RequestData.ReadInt64(); + + long parcelPtr = context.Request.ReceiveBuff[0].Position; + + Display disp = _displays.GetData((int)displayId); + + byte[] parcel = MakeIGraphicsBufferProducer(parcelPtr); + + context.Memory.WriteBytes(parcelPtr, parcel); + + context.ResponseData.Write(0L); + context.ResponseData.Write((long)parcel.Length); + + return ResultCode.Success; + } + + [Command(2031)] + // DestroyStrayLayer(u64) + public ResultCode DestroyStrayLayer(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(2101)] + // SetLayerScalingMode(u32, u64) + public ResultCode SetLayerScalingMode(ServiceCtx context) + { + int scalingMode = context.RequestData.ReadInt32(); + long unknown = context.RequestData.ReadInt64(); + + return ResultCode.Success; + } + + [Command(2102)] // 5.0.0+ + // ConvertScalingMode(unknown) -> unknown + public ResultCode ConvertScalingMode(ServiceCtx context) + { + SourceScalingMode scalingMode = (SourceScalingMode)context.RequestData.ReadInt32(); + + DestinationScalingMode? convertedScalingMode = ConvertScalingMode(scalingMode); + + if (!convertedScalingMode.HasValue) + { + // Scaling mode out of the range of valid values. + return ResultCode.InvalidArguments; + } + + if (scalingMode != SourceScalingMode.ScaleToWindow && + scalingMode != SourceScalingMode.PreserveAspectRatio) + { + // Invalid scaling mode specified. + return ResultCode.InvalidScalingMode; + } + + context.ResponseData.Write((ulong)convertedScalingMode); + + return ResultCode.Success; + } + + private DestinationScalingMode? ConvertScalingMode(SourceScalingMode source) + { + switch (source) + { + case SourceScalingMode.None: return DestinationScalingMode.None; + case SourceScalingMode.Freeze: return DestinationScalingMode.Freeze; + case SourceScalingMode.ScaleAndCrop: return DestinationScalingMode.ScaleAndCrop; + case SourceScalingMode.ScaleToWindow: return DestinationScalingMode.ScaleToWindow; + case SourceScalingMode.PreserveAspectRatio: return DestinationScalingMode.PreserveAspectRatio; + } + + return null; + } + + [Command(5202)] + // GetDisplayVsyncEvent(u64) -> handle + public ResultCode GetDisplayVSyncEvent(ServiceCtx context) + { + string name = GetDisplayName(context); + + if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + private byte[] MakeIGraphicsBufferProducer(long basePtr) + { + long id = 0x20; + long cookiePtr = 0L; + + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(ms); + + // flat_binder_object (size is 0x28) + writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) + writer.Write(0); //Flags + writer.Write((int)(id >> 0)); + writer.Write((int)(id >> 32)); + writer.Write((int)(cookiePtr >> 0)); + writer.Write((int)(cookiePtr >> 32)); + writer.Write((byte)'d'); + writer.Write((byte)'i'); + writer.Write((byte)'s'); + writer.Write((byte)'p'); + writer.Write((byte)'d'); + writer.Write((byte)'r'); + writer.Write((byte)'v'); + writer.Write((byte)'\0'); + writer.Write(0L); //Pad + + return MakeParcel(ms.ToArray(), new byte[] { 0, 0, 0, 0 }); + } + } + + private string GetDisplayName(ServiceCtx context) + { + string name = string.Empty; + + for (int index = 0; index < 8 && + context.RequestData.BaseStream.Position < + context.RequestData.BaseStream.Length; index++) + { + byte chr = context.RequestData.ReadByte(); + + if (chr >= 0x20 && chr < 0x7f) + { + name += (char)chr; + } + } + + return name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs b/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs deleted file mode 100644 index 3adf1d33..00000000 --- a/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Vi -{ - enum SrcScalingMode - { - None = 0, - Freeze = 1, - ScaleToWindow = 2, - ScaleAndCrop = 3, - PreserveAspectRatio = 4 - } - - enum DstScalingMode - { - Freeze = 0, - ScaleToWindow = 1, - ScaleAndCrop = 2, - None = 3, - PreserveAspectRatio = 4 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/IInfraManager.cs b/Ryujinx.HLE/HOS/Services/Wlan/IInfraManager.cs new file mode 100644 index 00000000..0416868a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/IInfraManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:inf")] + class IInfraManager : IpcService + { + public IInfraManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetActionFrame.cs b/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetActionFrame.cs new file mode 100644 index 00000000..6c2e20a4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetActionFrame.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:lga")] + class ILocalGetActionFrame : IpcService + { + public ILocalGetActionFrame(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetFrame.cs b/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetFrame.cs new file mode 100644 index 00000000..a224a192 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/ILocalGetFrame.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:lg")] + class ILocalGetFrame : IpcService + { + public ILocalGetFrame(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/ILocalManager.cs b/Ryujinx.HLE/HOS/Services/Wlan/ILocalManager.cs new file mode 100644 index 00000000..4cc2c4b2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/ILocalManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:lcl")] + class ILocalManager : IpcService + { + public ILocalManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/ISocketGetFrame.cs b/Ryujinx.HLE/HOS/Services/Wlan/ISocketGetFrame.cs new file mode 100644 index 00000000..ab5b2193 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/ISocketGetFrame.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:sg")] + class ISocketGetFrame : IpcService + { + public ISocketGetFrame(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/ISocketManager.cs b/Ryujinx.HLE/HOS/Services/Wlan/ISocketManager.cs new file mode 100644 index 00000000..afa1bede --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/ISocketManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:soc")] + class ISocketManager : IpcService + { + public ISocketManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Wlan/IUnknown1.cs b/Ryujinx.HLE/HOS/Services/Wlan/IUnknown1.cs new file mode 100644 index 00000000..dfae18e5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Wlan/IUnknown1.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Wlan +{ + [Service("wlan:dtc")] // 6.0.0+ + class IUnknown1 : IpcService + { + public IUnknown1(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs index 1fd27505..341f2a31 100644 --- a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs +++ b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs @@ -1,5 +1,5 @@ using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Am; +using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy; using System.Collections.Concurrent; namespace Ryujinx.HLE.HOS.SystemState diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs index 97fa1d74..2c3b188f 100644 --- a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs +++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.Services.Acc; +using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.Utilities; using System; -- cgit v1.2.3