Преглед изворни кода

Refactoring commands handling (#728)

* Refactoring commands handling

- Use Reflection to handle commands ID.
- Add all symbols (from SwIPC so not all time accurate).
- Re-sort some services commands methods.
- Some cleanup.
- Keep some empty constructor for consistency.

* Fix order in IProfile
Ac_K пре 7 година
родитељ
комит
560ccbeb2d
99 измењених фајлова са 994 додато и 1942 уклоњено
  1. 2 2
      Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs
  2. 15 34
      Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs
  3. 3 14
      Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs
  4. 17 25
      Ryujinx.HLE/HOS/Services/Acc/IProfile.cs
  5. 3 14
      Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs
  6. 1 14
      Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs
  7. 20 22
      Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs
  8. 17 21
      Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs
  9. 3 14
      Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs
  10. 12 18
      Ryujinx.HLE/HOS/Services/Am/IAudioController.cs
  11. 17 18
      Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs
  12. 1 14
      Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs
  13. 1 14
      Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs
  14. 1 14
      Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs
  15. 5 12
      Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs
  16. 10 14
      Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs
  17. 5 15
      Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs
  18. 27 51
      Ryujinx.HLE/HOS/Services/Am/ISelfController.cs
  19. 2 12
      Ryujinx.HLE/HOS/Services/Am/IStorage.cs
  20. 6 13
      Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs
  21. 21 23
      Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs
  22. 5 14
      Ryujinx.HLE/HOS/Services/Am/IWindowController.cs
  23. 3 14
      Ryujinx.HLE/HOS/Services/Apm/IManager.cs
  24. 5 14
      Ryujinx.HLE/HOS/Services/Apm/ISession.cs
  25. 21 23
      Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs
  26. 16 20
      Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs
  27. 23 21
      Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs
  28. 15 22
      Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs
  29. 8 16
      Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs
  30. 16 24
      Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs
  31. 6 16
      Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs
  32. 2 16
      Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs
  33. 2 16
      Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs
  34. 5 15
      Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs
  35. 30 41
      Ryujinx.HLE/HOS/Services/Bsd/IClient.cs
  36. 1 14
      Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs
  37. 1 14
      Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs
  38. 12 0
      Ryujinx.HLE/HOS/Services/CommandAttributes.cs
  39. 2 10
      Ryujinx.HLE/HOS/Services/DummyService.cs
  40. 2 15
      Ryujinx.HLE/HOS/Services/Es/IETicketService.cs
  41. 0 16
      Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs
  42. 10 86
      Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs
  43. 3 12
      Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs
  44. 4 14
      Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs
  45. 3 13
      Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs
  46. 5 15
      Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs
  47. 15 25
      Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
  48. 12 23
      Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs
  49. 3 12
      Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs
  50. 3 14
      Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs
  51. 2 10
      Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs
  52. 102 125
      Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
  53. 6 29
      Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
  54. 2 2
      Ryujinx.HLE/HOS/Services/IIpcService.cs
  55. 19 6
      Ryujinx.HLE/HOS/Services/IpcService.cs
  56. 6 14
      Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs
  57. 3 14
      Ryujinx.HLE/HOS/Services/Lm/ILogService.cs
  58. 4 15
      Ryujinx.HLE/HOS/Services/Lm/ILogger.cs
  59. 105 115
      Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs
  60. 4 15
      Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs
  61. 9 20
      Ryujinx.HLE/HOS/Services/Mm/IRequest.cs
  62. 2 15
      Ryujinx.HLE/HOS/Services/Ncm/IContentManager.cs
  63. 3 16
      Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs
  64. 27 37
      Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs
  65. 4 15
      Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUserManager.cs
  66. 6 15
      Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs
  67. 12 15
      Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs
  68. 5 15
      Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs
  69. 5 14
      Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs
  70. 4 14
      Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs
  71. 3 14
      Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs
  72. 1 14
      Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs
  73. 1 14
      Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs
  74. 19 18
      Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
  75. 4 12
      Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs
  76. 5 15
      Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs
  77. 13 17
      Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs
  78. 3 15
      Ryujinx.HLE/HOS/Services/Pm/IShellInterface.cs
  79. 3 13
      Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs
  80. 4 15
      Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs
  81. 5 14
      Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs
  82. 9 23
      Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs
  83. 7 18
      Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs
  84. 11 21
      Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs
  85. 8 12
      Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
  86. 3 12
      Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs
  87. 1 14
      Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs
  88. 3 14
      Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs
  89. 8 31
      Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
  90. 6 13
      Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
  91. 13 23
      Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs
  92. 11 24
      Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
  93. 32 26
      Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs
  94. 3 14
      Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs
  95. 24 29
      Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs
  96. 19 13
      Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs
  97. 3 14
      Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs
  98. 17 12
      Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs
  99. 3 14
      Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs

+ 2 - 2
Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs

@@ -63,13 +63,13 @@ namespace Ryujinx.HLE.Exceptions
                 var ipcCommands = ipcService.Commands;
 
                 // Find the handler for the method called
-                var ipcHandler   = ipcCommands.FirstOrDefault(x => x.Value.Method == callingMethod);
+                var ipcHandler   = ipcCommands.FirstOrDefault(x => x.Value as MethodBase == callingMethod);
                 var ipcCommandId = ipcHandler.Key;
                 var ipcMethod    = ipcHandler.Value;
 
                 if (ipcMethod != null)
                 {
-                    sb.AppendLine($"Service Command: {ipcService.GetType().FullName}: {ipcCommandId} ({ipcMethod.Method.Name})");
+                    sb.AppendLine($"Service Command: {ipcService.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
                     sb.AppendLine();
                 }
             }

+ 15 - 34
Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs

@@ -1,6 +1,5 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Services.Arp;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Utilities;
@@ -19,40 +18,9 @@ namespace Ryujinx.HLE.HOS.Services.Acc
 
         private ApplicationLaunchProperty _applicationLaunchProperty;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAccountService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,   GetUserCount                         },
-                { 1,   GetUserExistence                     },
-                { 2,   ListAllUsers                         },
-                { 3,   ListOpenUsers                        },
-                { 4,   GetLastOpenedUser                    },
-                { 5,   GetProfile                           },
-              //{ 6,   GetProfileDigest                     }, // 3.0.0+
-                { 50,  IsUserRegistrationRequestPermitted   },
-                { 51,  TrySelectUserWithoutInteraction      },
-              //{ 60,  ListOpenContextStoredUsers           }, // 5.0.0-5.1.0
-              //{ 99,  DebugActivateOpenContextRetention    }, // 6.0.0+
-                { 100, InitializeApplicationInfo            },
-                { 101, GetBaasAccountManagerForApplication  },
-              //{ 102, AuthenticateApplicationAsync         },
-              //{ 103, CheckNetworkServiceAvailabilityAsync }, // 4.0.0+
-                { 110, StoreSaveDataThumbnail               },
-                { 111, ClearSaveDataThumbnail               },
-              //{ 120, CreateGuestLoginRequest              },
-              //{ 130, LoadOpenContext                      }, // 6.0.0+
-              //{ 131, ListOpenContextStoredUsers           }, // 6.0.0+
-                { 140, InitializeApplicationInfo            }, // 6.0.0+
-              //{ 141, ListQualifiedUsers                   }, // 6.0.0+
-                { 150, IsUserAccountSwitchLocked            }, // 6.0.0+
-            };
-        }
+        public IAccountService(ServiceCtx context) { }
 
+        [Command(0)]
         // GetUserCount() -> i32
         public long GetUserCount(ServiceCtx context)
         {
@@ -61,6 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(1)]
         // GetUserExistence(nn::account::Uid) -> bool
         public long GetUserExistence(ServiceCtx context)
         {
@@ -76,12 +45,14 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(2)]
         // ListAllUsers() -> array<nn::account::Uid, 0xa>
         public long ListAllUsers(ServiceCtx context)
         {
             return WriteUserList(context, context.Device.System.State.Account.GetAllUsers());
         }
 
+        [Command(3)]
         // ListOpenUsers() -> array<nn::account::Uid, 0xa>
         public long ListOpenUsers(ServiceCtx context)
         {
@@ -116,6 +87,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(4)]
         // GetLastOpenedUser() -> nn::account::Uid
         public long GetLastOpenedUser(ServiceCtx context)
         {
@@ -124,6 +96,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(5)]
         // GetProfile(nn::account::Uid) -> object<nn::account::profile::IProfile>
         public long GetProfile(ServiceCtx context)
         {
@@ -144,6 +117,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(50)]
         // IsUserRegistrationRequestPermitted(u64, pid) -> bool
         public long IsUserRegistrationRequestPermitted(ServiceCtx context)
         {
@@ -153,6 +127,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(51)]
         // TrySelectUserWithoutInteraction(bool) -> nn::account::Uid
         public long TrySelectUserWithoutInteraction(ServiceCtx context)
         {
@@ -180,6 +155,8 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [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 long InitializeApplicationInfo(ServiceCtx context)
@@ -225,6 +202,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(101)]
         // GetBaasAccountManagerForApplication(nn::account::Uid) -> object<nn::account::baas::IManagerForApplication>
         public long GetBaasAccountManagerForApplication(ServiceCtx context)
         {
@@ -248,6 +226,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(110)]
         // StoreSaveDataThumbnail(nn::account::Uid, buffer<bytes, 5>)
         public long StoreSaveDataThumbnail(ServiceCtx context)
         {
@@ -285,6 +264,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(111)]
         // ClearSaveDataThumbnail(nn::account::Uid)
         public long ClearSaveDataThumbnail(ServiceCtx context)
         {
@@ -307,6 +287,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(150)] // 6.0.0+
         // IsUserAccountSwitchLocked() -> bool
         public long IsUserAccountSwitchLocked(ServiceCtx context)
         {

+ 3 - 14
Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs

@@ -1,33 +1,21 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Services.Arp;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Acc
 {
     class IManagerForApplication : IpcService
     {
-        private UInt128 _userId;
-
+        private UInt128                   _userId;
         private ApplicationLaunchProperty _applicationLaunchProperty;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IManagerForApplication(UInt128 userId, ApplicationLaunchProperty applicationLaunchProperty)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, CheckAvailability },
-                { 1, GetAccountId      }
-            };
-
             _userId                    = userId;
             _applicationLaunchProperty = applicationLaunchProperty;
         }
 
+        [Command(0)]
         // CheckAvailability()
         public long CheckAvailability(ServiceCtx context)
         {
@@ -36,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(1)]
         // GetAccountId() -> nn::account::NetworkServiceAccountId
         public long GetAccountId(ServiceCtx context)
         {

+ 17 - 25
Ryujinx.HLE/HOS/Services/Acc/IProfile.cs

@@ -1,9 +1,7 @@
 using ChocolArm64.Memory;
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
 using System.Text;
@@ -12,29 +10,17 @@ namespace Ryujinx.HLE.HOS.Services.Acc
 {
     class IProfile : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private UserProfile _profile;
-
-        private Stream _profilePictureStream;
+        private Stream      _profilePictureStream;
 
         public IProfile(UserProfile profile)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  Get          },
-                { 1,  GetBase      },
-                { 10, GetImageSize },
-                { 11, LoadImage    }
-            };
-
-            _profile = profile;
-
+            _profile              = profile;
             _profilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg");
         }
 
+        [Command(0)]
+        // Get() -> (nn::account::profile::ProfileBase, buffer<nn::account::profile::UserData, 0x1a>)
         public long Get(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAcc);
@@ -50,6 +36,8 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return GetBase(context);
         }
 
+        [Command(1)]
+        // GetBase() -> nn::account::profile::ProfileBase
         public long GetBase(ServiceCtx context)
         {
             _profile.UserId.Write(context.ResponseData);
@@ -63,6 +51,17 @@ namespace Ryujinx.HLE.HOS.Services.Acc
             return 0;
         }
 
+        [Command(10)]
+        // GetImageSize() -> u32
+        private long GetImageSize(ServiceCtx context)
+        {
+            context.ResponseData.Write(_profilePictureStream.Length);
+
+            return 0;
+        }
+
+        [Command(11)]
+        // LoadImage() -> (u32, buffer<bytes, 6>)
         private long LoadImage(ServiceCtx context)
         {
             long bufferPosition = context.Request.ReceiveBuff[0].Position;
@@ -78,12 +77,5 @@ namespace Ryujinx.HLE.HOS.Services.Acc
 
             return 0;
         }
-
-        private long GetImageSize(ServiceCtx context)
-        {
-            context.ResponseData.Write(_profilePictureStream.Length);
-
-            return 0;
-        }
     }
 }

+ 3 - 14
Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     [Service("appletAE")]
     class IAllSystemAppletProxiesService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAllSystemAppletProxiesService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 100, OpenSystemAppletProxy }
-            };
-        }
+        public IAllSystemAppletProxiesService(ServiceCtx context) { }
 
+        [Command(100)]
+        // OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
         public long OpenSystemAppletProxy(ServiceCtx context)
         {
             MakeObject(context, new ISystemAppletProxy());

+ 1 - 14
Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IApplicationCreator : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationCreator()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IApplicationCreator() { }
     }
 }

+ 20 - 22
Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs

@@ -1,31 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IApplicationFunctions : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationFunctions()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 1,  PopLaunchParameter          },
-                { 20, EnsureSaveData              },
-                { 21, GetDesiredLanguage          },
-                { 22, SetTerminateResult          },
-                { 23, GetDisplayVersion           },
-                { 40, NotifyRunning               },
-                { 50, GetPseudoDeviceId           },
-                { 66, InitializeGamePlayRecording },
-                { 67, SetGamePlayRecordingState   }
-            };
-        }
+        public IApplicationFunctions() { }
 
+        [Command(1)]
+        // PopLaunchParameter(u32) -> object<nn::am::service::IStorage>
         public long PopLaunchParameter(ServiceCtx context)
         {
             // Only the first 0x18 bytes of the Data seems to be actually used.
@@ -34,6 +16,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(20)]
+        // EnsureSaveData(nn::account::Uid) -> u64
         public long EnsureSaveData(ServiceCtx context)
         {
             long uIdLow  = context.RequestData.ReadInt64();
@@ -46,6 +30,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(21)]
+        // GetDesiredLanguage() -> nn::settings::LanguageCode
         public long GetDesiredLanguage(ServiceCtx context)
         {
             context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode);
@@ -53,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(22)]
+        // SetTerminateResult(u32)
         public long SetTerminateResult(ServiceCtx context)
         {
             int errorCode = context.RequestData.ReadInt32();
@@ -72,6 +60,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return $"{(2000 + module):d4}-{description:d4}";
         }
 
+        [Command(23)]
+        // GetDisplayVersion() -> nn::oe::DisplayVersion
         public long GetDisplayVersion(ServiceCtx context)
         {
             // FIXME: Need to check correct version on a switch.
@@ -81,6 +71,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(40)]
+        // NotifyRunning() -> b8
         public long NotifyRunning(ServiceCtx context)
         {
             context.ResponseData.Write(1);
@@ -88,6 +80,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(50)] // 2.0.0+
+        // GetPseudoDeviceId() -> nn::util::Uuid
         public long GetPseudoDeviceId(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -98,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(66)] // 3.0.0+
+        // InitializeGamePlayRecording(u64, handle<copy>)
         public long InitializeGamePlayRecording(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -105,6 +101,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(67)] // 3.0.0+
+        // SetGamePlayRecordingState(u32)
         public long SetGamePlayRecordingState(ServiceCtx context)
         {
             int state = context.RequestData.ReadInt32();
@@ -114,4 +112,4 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
     }
-}
+}

+ 17 - 21
Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs

@@ -1,29 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IApplicationProxy : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationProxy()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,    GetCommonStateGetter    },
-                { 1,    GetSelfController       },
-                { 2,    GetWindowController     },
-                { 3,    GetAudioController      },
-                { 4,    GetDisplayController    },
-                { 11,   GetLibraryAppletCreator },
-                { 20,   GetApplicationFunctions },
-                { 1000, GetDebugFunctions       }
-            };
-        }
+        public IApplicationProxy() { }
 
+        [Command(0)]
+        // GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
         public long GetCommonStateGetter(ServiceCtx context)
         {
             MakeObject(context, new ICommonStateGetter(context.Device.System));
@@ -31,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1)]
+        // GetSelfController() -> object<nn::am::service::ISelfController>
         public long GetSelfController(ServiceCtx context)
         {
             MakeObject(context, new ISelfController(context.Device.System));
@@ -38,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(2)]
+        // GetWindowController() -> object<nn::am::service::IWindowController>
         public long GetWindowController(ServiceCtx context)
         {
             MakeObject(context, new IWindowController());
@@ -45,6 +31,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(3)]
+        // GetAudioController() -> object<nn::am::service::IAudioController>
         public long GetAudioController(ServiceCtx context)
         {
             MakeObject(context, new IAudioController());
@@ -52,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(4)]
+        // GetDisplayController() -> object<nn::am::service::IDisplayController>
         public long GetDisplayController(ServiceCtx context)
         {
             MakeObject(context, new IDisplayController());
@@ -59,6 +49,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(11)]
+        // GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
         public long GetLibraryAppletCreator(ServiceCtx context)
         {
             MakeObject(context, new ILibraryAppletCreator());
@@ -66,6 +58,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(20)]
+        // GetApplicationFunctions() -> object<nn::am::service::IApplicationFunctions>
         public long GetApplicationFunctions(ServiceCtx context)
         {
             MakeObject(context, new IApplicationFunctions());
@@ -73,6 +67,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1000)]
+        // GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
         public long GetDebugFunctions(ServiceCtx context)
         {
             MakeObject(context, new IDebugFunctions());

+ 3 - 14
Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     [Service("appletOE")]
     class IApplicationProxyService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationProxyService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, OpenApplicationProxy }
-            };
-        }
+        public IApplicationProxyService(ServiceCtx context) { }
 
+        [Command(0)]
+        // OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
         public long OpenApplicationProxy(ServiceCtx context)
         {
             MakeObject(context, new IApplicationProxy());

+ 12 - 18
Ryujinx.HLE/HOS/Services/Am/IAudioController.cs

@@ -1,27 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IAudioController : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAudioController()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, SetExpectedMasterVolume              },
-                { 1, GetMainAppletExpectedMasterVolume    },
-                { 2, GetLibraryAppletExpectedMasterVolume },
-                { 3, ChangeMainAppletMasterVolume         },
-                { 4, SetTransparentVolumeRate             }
-            };
-        }
+        public IAudioController() { }
 
+        [Command(0)]
+        // SetExpectedMasterVolume(f32, f32)
         public long SetExpectedMasterVolume(ServiceCtx context)
         {
             float appletVolume        = context.RequestData.ReadSingle();
@@ -32,6 +18,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1)]
+        // GetMainAppletExpectedMasterVolume() -> f32
         public long GetMainAppletExpectedMasterVolume(ServiceCtx context)
         {
             context.ResponseData.Write(1f);
@@ -41,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(2)]
+        // GetLibraryAppletExpectedMasterVolume() -> f32
         public long GetLibraryAppletExpectedMasterVolume(ServiceCtx context)
         {
             context.ResponseData.Write(1f);
@@ -50,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(3)]
+        // ChangeMainAppletMasterVolume(f32, u64)
         public long ChangeMainAppletMasterVolume(ServiceCtx context)
         {
             float unknown0 = context.RequestData.ReadSingle();
@@ -60,6 +52,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(4)]
+        // SetTransparentVolumeRate(f32)
         public long SetTransparentVolumeRate(ServiceCtx context)
         {
             float unknown0 = context.RequestData.ReadSingle();
@@ -69,4 +63,4 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
     }
-}
+}

+ 17 - 18
Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs

@@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -11,29 +10,15 @@ namespace Ryujinx.HLE.HOS.Services.Am
 {
     class ICommonStateGetter : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _displayResolutionChangeEvent;
 
         public ICommonStateGetter(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  GetEventHandle                          },
-                { 1,  ReceiveMessage                          },
-                { 5,  GetOperationMode                        },
-                { 6,  GetPerformanceMode                      },
-                { 8,  GetBootMode                             },
-                { 9,  GetCurrentFocusState                    },
-                { 60, GetDefaultDisplayResolution             },
-                { 61, GetDefaultDisplayResolutionChangeEvent  }
-            };
-
             _displayResolutionChangeEvent = new KEvent(system);
         }
 
+        [Command(0)]
+        // GetEventHandle() -> handle<copy>
         public long GetEventHandle(ServiceCtx context)
         {
             KEvent Event = context.Device.System.AppletState.MessageEvent;
@@ -48,6 +33,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1)]
+        // ReceiveMessage() -> nn::am::AppletMessage
         public long ReceiveMessage(ServiceCtx context)
         {
             if (!context.Device.System.AppletState.TryDequeueMessage(out MessageInfo message))
@@ -60,6 +47,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(5)]
+        // GetOperationMode() -> u8
         public long GetOperationMode(ServiceCtx context)
         {
             OperationMode mode = context.Device.System.State.DockedMode
@@ -71,6 +60,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(6)]
+        // GetPerformanceMode() -> u32
         public long GetPerformanceMode(ServiceCtx context)
         {
             Apm.PerformanceMode mode = context.Device.System.State.DockedMode
@@ -82,6 +73,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(8)]
+        // GetBootMode() -> u8
         public long GetBootMode(ServiceCtx context)
         {
             context.ResponseData.Write((byte)0); //Unknown value.
@@ -91,6 +84,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(9)]
+        // GetCurrentFocusState() -> u8
         public long GetCurrentFocusState(ServiceCtx context)
         {
             context.ResponseData.Write((byte)context.Device.System.AppletState.FocusState);
@@ -98,6 +93,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(60)] // 3.0.0+
+        // GetDefaultDisplayResolution() -> (u32, u32)
         public long GetDefaultDisplayResolution(ServiceCtx context)
         {
             context.ResponseData.Write(1280);
@@ -106,6 +103,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(61)] // 3.0.0+
+        // GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
         public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_displayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -120,4 +119,4 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
     }
-}
+}

+ 1 - 14
Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IDebugFunctions : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IDebugFunctions()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IDebugFunctions() { }
     }
 }

+ 1 - 14
Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IDisplayController : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IDisplayController()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IDisplayController() { }
     }
 }

+ 1 - 14
Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IGlobalStateController : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IGlobalStateController()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IGlobalStateController() { }
     }
 }

+ 5 - 12
Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs

@@ -3,30 +3,21 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IHomeMenuFunctions : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _channelEvent;
 
         public IHomeMenuFunctions(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 10, RequestToGetForeground        },
-                { 21, GetPopFromGeneralChannelEvent }
-            };
-
             // TODO: Signal this Event somewhere in future.
             _channelEvent = new KEvent(system);
         }
 
+        [Command(10)]
+        // RequestToGetForeground()
         public long RequestToGetForeground(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -34,6 +25,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(21)]
+        // GetPopFromGeneralChannelEvent() -> handle<copy>
         public long GetPopFromGeneralChannelEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -48,4 +41,4 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
     }
-}
+}

+ 10 - 14
Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs

@@ -3,32 +3,20 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class ILibraryAppletAccessor : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _stateChangedEvent;
 
         public ILibraryAppletAccessor(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,   GetAppletStateChangedEvent },
-                { 10,  Start                      },
-                { 30,  GetResult                  },
-                { 100, PushInData                 },
-                { 101, PopOutData                 }
-            };
-
             _stateChangedEvent = new KEvent(system);
         }
 
+        [Command(0)]
+        // GetAppletStateChangedEvent() -> handle<copy>
         public long GetAppletStateChangedEvent(ServiceCtx context)
         {
             _stateChangedEvent.ReadableEvent.Signal();
@@ -45,6 +33,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(10)]
+        // Start()
         public long Start(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -52,6 +42,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(30)]
+        // GetResult()
         public long GetResult(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -59,6 +51,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(100)]
+        // PushInData(object<nn::am::service::IStorage>)
         public long PushInData(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -66,6 +60,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(101)]
+        // PopOutData() -> object<nn::am::service::IStorage>
         public long PopOutData(ServiceCtx context)
         {
             MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams()));

+ 5 - 15
Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs

@@ -1,23 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class ILibraryAppletCreator : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ILibraryAppletCreator()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  CreateLibraryApplet },
-                { 10, CreateStorage       }
-            };
-        }
+        public ILibraryAppletCreator() { }
 
+        [Command(0)]
+        // CreateLibraryApplet(u32, u32) -> object<nn::am::service::ILibraryAppletAccessor>
         public long CreateLibraryApplet(ServiceCtx context)
         {
             MakeObject(context, new ILibraryAppletAccessor(context.Device.System));
@@ -25,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(10)]
+        // CreateStorage(u64) -> object<nn::am::service::IStorage>
         public long CreateStorage(ServiceCtx context)
         {
             long size = context.RequestData.ReadInt64();

+ 27 - 51
Ryujinx.HLE/HOS/Services/Am/ISelfController.cs

@@ -3,16 +3,11 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class ISelfController : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _libraryAppletLaunchableEvent;
 
         private KEvent _accumulatedSuspendedTickChangedEvent;
@@ -22,54 +17,11 @@ namespace Ryujinx.HLE.HOS.Services.Am
 
         public ISelfController(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,    Exit                                        },
-                { 1,    LockExit                                    },
-                { 2,    UnlockExit                                  },
-              //{ 3,    EnterFatalSection                           }, // 2.0.0+
-              //{ 4,    LeaveFatalSection                           }, // 2.0.0+
-                { 9,    GetLibraryAppletLaunchableEvent             },
-                { 10,   SetScreenShotPermission                     },
-                { 11,   SetOperationModeChangedNotification         },
-                { 12,   SetPerformanceModeChangedNotification       },
-                { 13,   SetFocusHandlingMode                        },
-                { 14,   SetRestartMessageEnabled                    },
-              //{ 15,   SetScreenShotAppletIdentityInfo             }, // 2.0.0+
-                { 16,   SetOutOfFocusSuspendingEnabled              }, // 2.0.0+
-              //{ 17,   SetControllerFirmwareUpdateSection          }, // 3.0.0+
-              //{ 18,   SetRequiresCaptureButtonShortPressedMessage }, // 3.0.0+
-                { 19,   SetScreenShotImageOrientation               }, // 3.0.0+
-              //{ 20,   SetDesirableKeyboardLayout                  }, // 4.0.0+
-              //{ 40,   CreateManagedDisplayLayer                   },
-              //{ 41,   IsSystemBufferSharingEnabled                }, // 4.0.0+
-              //{ 42,   GetSystemSharedLayerHandle                  }, // 4.0.0+
-              //{ 43,   GetSystemSharedBufferHandle                 }, // 5.0.0+
-                { 50,   SetHandlesRequestToDisplay                  },
-              //{ 51,   ApproveToDisplay                            },
-              //{ 60,   OverrideAutoSleepTimeAndDimmingTime         },
-              //{ 61,   SetMediaPlaybackState                       },
-                { 62,   SetIdleTimeDetectionExtension               },
-                { 63,   GetIdleTimeDetectionExtension               },
-              //{ 64,   SetInputDetectionSourceSet                  },
-              //{ 65,   ReportUserIsActive                          }, // 2.0.0+
-              //{ 66,   GetCurrentIlluminance                       }, // 3.0.0+
-              //{ 67,   IsIlluminanceAvailable                      }, // 3.0.0+
-              //{ 68,   SetAutoSleepDisabled                        }, // 5.0.0+
-              //{ 69,   IsAutoSleepDisabled                         }, // 5.0.0+
-              //{ 70,   ReportMultimediaError                       }, // 4.0.0+
-              //{ 71,   GetCurrentIlluminanceEx                     }, // 5.0.0+
-              //{ 80,   SetWirelessPriorityMode                     }, // 4.0.0+
-              //{ 90,   GetAccumulatedSuspendedTickValue            }, // 6.0.0+
-                { 91,   GetAccumulatedSuspendedTickChangedEvent     }, // 6.0.0+
-              //{ 100,  SetAlbumImageTakenNotificationEnabled       }, // 7.0.0+
-              //{ 110,  SetApplicationAlbumUserData                 }, // 8.0.0+
-              //{ 1000, GetDebugStorageChannel                      }, // 7.0.0+
-            };
-
             _libraryAppletLaunchableEvent = new KEvent(system);
         }
 
+        [Command(0)]
+        // Exit()
         public long Exit(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -77,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1)]
+        // LockExit()
         public long LockExit(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -84,6 +38,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(2)]
+        // UnlockExit()
         public long UnlockExit(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -91,6 +47,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(9)]
+        // GetLibraryAppletLaunchableEvent() -> handle<copy>
         public long GetLibraryAppletLaunchableEvent(ServiceCtx context)
         {
             _libraryAppletLaunchableEvent.ReadableEvent.Signal();
@@ -107,6 +65,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(10)]
+        // SetScreenShotPermission(u32)
         public long SetScreenShotPermission(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -116,6 +76,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(11)]
+        // SetOperationModeChangedNotification(b8)
         public long SetOperationModeChangedNotification(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -125,6 +87,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(12)]
+        // SetPerformanceModeChangedNotification(b8)
         public long SetPerformanceModeChangedNotification(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -134,6 +98,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(13)]
+        // SetFocusHandlingMode(b8, b8, b8)
         public long SetFocusHandlingMode(ServiceCtx context)
         {
             bool flag1 = context.RequestData.ReadByte() != 0;
@@ -145,6 +111,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(14)]
+        // SetRestartMessageEnabled(b8)
         public long SetRestartMessageEnabled(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -154,6 +122,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(16)] // 2.0.0+
+        // SetOutOfFocusSuspendingEnabled(b8)
         public long SetOutOfFocusSuspendingEnabled(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -163,6 +133,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(19)] // 3.0.0+
         public long SetScreenShotImageOrientation(ServiceCtx context)
         {
             int orientation = context.RequestData.ReadInt32();
@@ -172,6 +143,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(50)]
+        // SetHandlesRequestToDisplay(b8)
         public long SetHandlesRequestToDisplay(ServiceCtx context)
         {
             bool enable = context.RequestData.ReadByte() != 0;
@@ -181,6 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(62)]
         // SetIdleTimeDetectionExtension(u32)
         public long SetIdleTimeDetectionExtension(ServiceCtx context)
         {
@@ -191,6 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(63)]
         // GetIdleTimeDetectionExtension() -> u32
         public long GetIdleTimeDetectionExtension(ServiceCtx context)
         {
@@ -201,6 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(91)] // 6.0.0+
         // GetAccumulatedSuspendedTickChangedEvent() -> handle<copy>
         public long GetAccumulatedSuspendedTickChangedEvent(ServiceCtx context)
         {
@@ -221,4 +197,4 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
     }
-}
+}

+ 2 - 12
Ryujinx.HLE/HOS/Services/Am/IStorage.cs

@@ -1,26 +1,16 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IStorage : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public byte[] Data { get; private set; }
 
         public IStorage(byte[] data)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Open }
-            };
-
             Data = data;
         }
 
+        [Command(0)]
+        // Open() -> object<nn::am::service::IStorageAccessor>
         public long Open(ServiceCtx context)
         {
             MakeObject(context, new IStorageAccessor(this));

+ 6 - 13
Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs

@@ -1,29 +1,18 @@
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IStorageAccessor : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private IStorage _storage;
 
         public IStorageAccessor(IStorage storage)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  GetSize },
-                { 10, Write   },
-                { 11, Read    }
-            };
-
             _storage = storage;
         }
 
+        [Command(0)]
+        // GetSize() -> u64
         public long GetSize(ServiceCtx context)
         {
             context.ResponseData.Write((long)_storage.Data.Length);
@@ -31,6 +20,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(10)]
+        // Write(u64, buffer<bytes, 0x21>)
         public long Write(ServiceCtx context)
         {
             // TODO: Error conditions.
@@ -55,6 +46,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(11)]
+        // Read(u64) -> buffer<bytes, 0x22>
         public long Read(ServiceCtx context)
         {
             // TODO: Error conditions.

+ 21 - 23
Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs

@@ -1,31 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class ISystemAppletProxy : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISystemAppletProxy()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,    GetCommonStateGetter     },
-                { 1,    GetSelfController        },
-                { 2,    GetWindowController      },
-                { 3,    GetAudioController       },
-                { 4,    GetDisplayController     },
-                { 11,   GetLibraryAppletCreator  },
-                { 20,   GetHomeMenuFunctions     },
-                { 21,   GetGlobalStateController },
-                { 22,   GetApplicationCreator    },
-                { 1000, GetDebugFunctions        }
-            };
-        }
+        public ISystemAppletProxy() { }
 
+        [Command(0)]
+        // GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
         public long GetCommonStateGetter(ServiceCtx context)
         {
             MakeObject(context, new ICommonStateGetter(context.Device.System));
@@ -33,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1)]
+        // GetSelfController() -> object<nn::am::service::ISelfController>
         public long GetSelfController(ServiceCtx context)
         {
             MakeObject(context, new ISelfController(context.Device.System));
@@ -40,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(2)]
+        // GetWindowController() -> object<nn::am::service::IWindowController>
         public long GetWindowController(ServiceCtx context)
         {
             MakeObject(context, new IWindowController());
@@ -47,6 +31,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(3)]
+        // GetAudioController() -> object<nn::am::service::IAudioController>
         public long GetAudioController(ServiceCtx context)
         {
             MakeObject(context, new IAudioController());
@@ -54,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(4)]
+        // GetDisplayController() -> object<nn::am::service::IDisplayController>
         public long GetDisplayController(ServiceCtx context)
         {
             MakeObject(context, new IDisplayController());
@@ -61,6 +49,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(11)]
+        // GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
         public long GetLibraryAppletCreator(ServiceCtx context)
         {
             MakeObject(context, new ILibraryAppletCreator());
@@ -68,6 +58,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(20)]
+        // GetHomeMenuFunctions() -> object<nn::am::service::IHomeMenuFunctions>
         public long GetHomeMenuFunctions(ServiceCtx context)
         {
             MakeObject(context, new IHomeMenuFunctions(context.Device.System));
@@ -75,6 +67,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(21)]
+        // GetGlobalStateController() -> object<nn::am::service::IGlobalStateController>
         public long GetGlobalStateController(ServiceCtx context)
         {
             MakeObject(context, new IGlobalStateController());
@@ -82,6 +76,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(22)]
+        // GetApplicationCreator() -> object<nn::am::service::IApplicationCreator>
         public long GetApplicationCreator(ServiceCtx context)
         {
             MakeObject(context, new IApplicationCreator());
@@ -89,6 +85,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(1000)]
+        // GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
         public long GetDebugFunctions(ServiceCtx context)
         {
             MakeObject(context, new IDebugFunctions());

+ 5 - 14
Ryujinx.HLE/HOS/Services/Am/IWindowController.cs

@@ -1,24 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
 {
     class IWindowController : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IWindowController()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 1,  GetAppletResourceUserId },
-                { 10, AcquireForegroundRights }
-            };
-        }
+        public IWindowController() { }
 
+        [Command(1)]
+        // GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
         public long GetAppletResourceUserId(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);
@@ -28,6 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
             return 0;
         }
 
+        [Command(10)]
+        // AcquireForegroundRights()
         public long AcquireForegroundRights(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAm);

+ 3 - 14
Ryujinx.HLE/HOS/Services/Apm/IManager.cs

@@ -1,24 +1,13 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Apm
 {
     [Service("apm")]
     [Service("apm:p")]
     class IManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, OpenSession }
-            };
-        }
+        public IManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // OpenSession() -> object<nn::apm::ISession>
         public long OpenSession(ServiceCtx context)
         {
             MakeObject(context, new ISession());

+ 5 - 14
Ryujinx.HLE/HOS/Services/Apm/ISession.cs

@@ -1,24 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Apm
 {
     class ISession : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISession()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, SetPerformanceConfiguration },
-                { 1, GetPerformanceConfiguration }
-            };
-        }
+        public ISession() { }
 
+        [Command(0)]
+        // SetPerformanceConfiguration(nn::apm::PerformanceMode, nn::apm::PerformanceConfiguration)
         public long SetPerformanceConfiguration(ServiceCtx context)
         {
             PerformanceMode          perfMode   = (PerformanceMode)context.RequestData.ReadInt32();
@@ -27,6 +16,8 @@ namespace Ryujinx.HLE.HOS.Services.Apm
             return 0;
         }
 
+        [Command(1)]
+        // GetPerformanceConfiguration(nn::apm::PerformanceMode) -> nn::apm::PerformanceConfiguration
         public long GetPerformanceConfiguration(ServiceCtx context)
         {
             PerformanceMode perfMode = (PerformanceMode)context.RequestData.ReadInt32();

+ 21 - 23
Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs

@@ -4,42 +4,24 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
 {
     class IAudioOut : IpcService, IDisposable
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private IAalOutput _audioOut;
-
-        private KEvent _releaseEvent;
-
-        private int _track;
+        private KEvent     _releaseEvent;
+        private int        _track;
 
         public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetAudioOutState              },
-                { 1, StartAudioOut                 },
-                { 2, StopAudioOut                  },
-                { 3, AppendAudioOutBuffer          },
-                { 4, RegisterBufferEvent           },
-                { 5, GetReleasedAudioOutBuffer     },
-                { 6, ContainsAudioOutBuffer        },
-                { 7, AppendAudioOutBufferAuto      },
-                { 8, GetReleasedAudioOutBufferAuto }
-            };
-
             _audioOut     = audioOut;
             _releaseEvent = releaseEvent;
             _track        = track;
         }
 
+        [Command(0)]
+        // GetAudioOutState() -> u32 state
         public long GetAudioOutState(ServiceCtx context)
         {
             context.ResponseData.Write((int)_audioOut.GetState(_track));
@@ -47,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(1)]
+        // StartAudioOut()
         public long StartAudioOut(ServiceCtx context)
         {
             _audioOut.Start(_track);
@@ -54,6 +38,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(2)]
+        // StopAudioOut()
         public long StopAudioOut(ServiceCtx context)
         {
             _audioOut.Stop(_track);
@@ -61,11 +47,15 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(3)]
+        // AppendAudioOutBuffer(u64 tag, buffer<nn::audio::AudioOutBuffer, 5>)
         public long AppendAudioOutBuffer(ServiceCtx context)
         {
             return AppendAudioOutBufferImpl(context, context.Request.SendBuff[0].Position);
         }
 
+        [Command(4)]
+        // RegisterBufferEvent() -> handle<copy>
         public long RegisterBufferEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -78,6 +68,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(5)]
+        // GetReleasedAudioOutBuffer() -> (u32 count, buffer<nn::audio::AudioOutBuffer, 6>)
         public long GetReleasedAudioOutBuffer(ServiceCtx context)
         {
             long position = context.Request.ReceiveBuff[0].Position;
@@ -86,6 +78,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return GetReleasedAudioOutBufferImpl(context, position, size);
         }
 
+        [Command(6)]
+        // ContainsAudioOutBuffer(u64 tag) -> b8
         public long ContainsAudioOutBuffer(ServiceCtx context)
         {
             long tag = context.RequestData.ReadInt64();
@@ -95,6 +89,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(7)] // 3.0.0+
+        // AppendAudioOutBufferAuto(u64 tag, buffer<nn::audio::AudioOutBuffer, 0x21>)
         public long AppendAudioOutBufferAuto(ServiceCtx context)
         {
             (long position, long size) = context.Request.GetBufferType0x21();
@@ -119,6 +115,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             return 0;
         }
 
+        [Command(8)] // 3.0.0+
+        // GetReleasedAudioOutBufferAuto() -> (u32 count, buffer<nn::audio::AudioOutBuffer, 0x22>)
         public long GetReleasedAudioOutBufferAuto(ServiceCtx context)
         {
             (long position, long size) = context.Request.GetBufferType0x22();
@@ -162,4 +160,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
             }
         }
     }
-}
+}

+ 16 - 20
Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs

@@ -7,7 +7,6 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.Utilities;
 using System;
-using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 using System.Runtime.Intrinsics.X86;
@@ -23,10 +22,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
         // high latency).
         private const int MixBufferSamplesCount = 960;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _updateEvent;
 
         private MemoryManager _memory;
@@ -49,18 +44,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             IAalOutput             audioOut,
             AudioRendererParameter Params)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetSampleRate              },
-                { 1, GetSampleCount             },
-                { 2, GetMixBufferCount          },
-                { 3, GetState                   },
-                { 4, RequestUpdateAudioRenderer },
-                { 5, StartAudioRenderer         },
-                { 6, StopAudioRenderer          },
-                { 7, QuerySystemEvent           }
-            };
-
             _updateEvent = new KEvent(system);
 
             _memory   = memory;
@@ -81,7 +64,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             _playState = PlayState.Stopped;
         }
 
-        //  GetSampleRate() -> u32
+        [Command(0)]
+        // GetSampleRate() -> u32
         public long GetSampleRate(ServiceCtx context)
         {
             context.ResponseData.Write(_params.SampleRate);
@@ -89,7 +73,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
-        //  GetSampleCount() -> u32
+        [Command(1)]
+        // GetSampleCount() -> u32
         public long GetSampleCount(ServiceCtx context)
         {
             context.ResponseData.Write(_params.SampleCount);
@@ -97,6 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
+        [Command(2)]
         // GetMixBufferCount() -> u32
         public long GetMixBufferCount(ServiceCtx context)
         {
@@ -105,6 +91,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
+        [Command(3)]
         // GetState() -> u32
         private long GetState(ServiceCtx context)
         {
@@ -141,6 +128,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             _audioOut.Start(_track);
         }
 
+        [Command(4)]
+        // RequestUpdateAudioRenderer(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 5>)
+        // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>)
         public long RequestUpdateAudioRenderer(ServiceCtx context)
         {
             long outputPosition = context.Request.ReceiveBuff[0].Position;
@@ -247,6 +237,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
+        [Command(5)]
+        // Start()
         public long StartAudioRenderer(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAudio);
@@ -256,6 +248,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
+        [Command(6)]
+        // Stop()
         public long StopAudioRenderer(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceAudio);
@@ -265,6 +259,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             return 0;
         }
 
+        [Command(7)]
+        // QuerySystemEvent() -> handle<copy, event>
         public long QuerySystemEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -405,4 +401,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
             }
         }
     }
-}
+}

+ 23 - 21
Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs

@@ -4,42 +4,24 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.SystemState;
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 namespace Ryujinx.HLE.HOS.Services.Aud
 {
     class IAudioDevice : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _systemEvent;
 
         public IAudioDevice(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  ListAudioDeviceName            },
-                { 1,  SetAudioDeviceOutputVolume     },
-                { 3,  GetActiveAudioDeviceName       },
-                { 4,  QueryAudioDeviceSystemEvent    },
-                { 5,  GetActiveChannelCount          },
-                { 6,  ListAudioDeviceNameAuto        },
-                { 7,  SetAudioDeviceOutputVolumeAuto },
-                { 8,  GetAudioDeviceOutputVolumeAuto },
-                { 10, GetActiveAudioDeviceNameAuto   },
-                { 11, QueryAudioDeviceInputEvent     },
-                { 12, QueryAudioDeviceOutputEvent    }
-            };
-
             _systemEvent = new KEvent(system);
 
             // TODO: We shouldn't be signaling this here.
             _systemEvent.ReadableEvent.Signal();
         }
 
+        [Command(0)]
+        // ListAudioDeviceName() -> (u32, buffer<bytes, 6>)
         public long ListAudioDeviceName(ServiceCtx context)
         {
             string[] deviceNames = SystemStateMgr.AudioOutputs;
@@ -70,6 +52,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(1)]
+        // SetAudioDeviceOutputVolume(u32, buffer<bytes, 5>)
         public long SetAudioDeviceOutputVolume(ServiceCtx context)
         {
             float volume = context.RequestData.ReadSingle();
@@ -86,6 +70,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(3)]
+        // GetActiveAudioDeviceName() -> buffer<bytes, 6>
         public long GetActiveAudioDeviceName(ServiceCtx context)
         {
             string name = context.Device.System.State.ActiveAudioOutput;
@@ -107,6 +93,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(4)]
+        // QueryAudioDeviceSystemEvent() -> handle<copy, event>
         public long QueryAudioDeviceSystemEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -121,6 +109,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(5)]
+        // GetActiveChannelCount() -> u32
         public long GetActiveChannelCount(ServiceCtx context)
         {
             context.ResponseData.Write(2);
@@ -130,6 +120,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(6)]
+        // ListAudioDeviceNameAuto() -> (u32, buffer<bytes, 0x22>)
         public long ListAudioDeviceNameAuto(ServiceCtx context)
         {
             string[] deviceNames = SystemStateMgr.AudioOutputs;
@@ -159,6 +151,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(7)]
+        // SetAudioDeviceOutputVolumeAuto(u32, buffer<bytes, 0x21>)
         public long SetAudioDeviceOutputVolumeAuto(ServiceCtx context)
         {
             float volume = context.RequestData.ReadSingle();
@@ -174,6 +168,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(8)]
+        // GetAudioDeviceOutputVolumeAuto(buffer<bytes, 0x21>) -> u32
         public long GetAudioDeviceOutputVolumeAuto(ServiceCtx context)
         {
             context.ResponseData.Write(1f);
@@ -183,6 +179,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(10)]
+        // GetActiveAudioDeviceNameAuto() -> buffer<bytes, 0x22>
         public long GetActiveAudioDeviceNameAuto(ServiceCtx context)
         {
             string name = context.Device.System.State.ActiveAudioOutput;
@@ -203,6 +201,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(11)]
+        // QueryAudioDeviceInputEvent() -> handle<copy, event>
         public long QueryAudioDeviceInputEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -217,6 +217,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(12)]
+        // QueryAudioDeviceOutputEvent() -> handle<copy, event>
         public long QueryAudioDeviceOutputEvent(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
@@ -231,4 +233,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
     }
-}
+}

+ 15 - 22
Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs

@@ -1,10 +1,8 @@
 using ChocolArm64.Memory;
 using Ryujinx.Audio;
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Aud.AudioOut;
-using System.Collections.Generic;
 using System.Text;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
@@ -14,27 +12,14 @@ namespace Ryujinx.HLE.HOS.Services.Aud
     [Service("audout:u")]
     class IAudioOutManager : IpcService
     {
-        private const string DefaultAudioOutput = "DeviceOut";
+        private const string DefaultAudioOutput   = "DeviceOut";
+        private const int    DefaultSampleRate    = 48000;
+        private const int    DefaultChannelsCount = 2;
 
-        private const int DefaultSampleRate = 48000;
-
-        private const int DefaultChannelsCount = 2;
-
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAudioOutManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, ListAudioOuts     },
-                { 1, OpenAudioOut      },
-                { 2, ListAudioOutsAuto },
-                { 3, OpenAudioOutAuto  }
-            };
-        }
+        public IAudioOutManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
         public long ListAudioOuts(ServiceCtx context)
         {
             return ListAudioOutsImpl(
@@ -43,6 +28,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud
                 context.Request.ReceiveBuff[0].Size);
         }
 
+        [Command(1)]
+        // OpenAudioOut(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle<copy, process>, buffer<bytes, 5> name_in)
+        // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 6> name_out)
         public long OpenAudioOut(ServiceCtx context)
         {
             return OpenAudioOutImpl(
@@ -53,6 +41,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
                 context.Request.ReceiveBuff[0].Size);
         }
 
+        [Command(2)] // 3.0.0+
+        // ListAudioOutsAuto() -> (u32 count, buffer<bytes, 0x22>)
         public long ListAudioOutsAuto(ServiceCtx context)
         {
             (long recvPosition, long recvSize) = context.Request.GetBufferType0x22();
@@ -60,6 +50,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return ListAudioOutsImpl(context, recvPosition, recvSize);
         }
 
+        [Command(3)] // 3.0.0+
+        // OpenAudioOutAuto(u32 sample_rate, u16 unused, u16 channel_count, nn::applet::AppletResourceUserId, pid, handle<copy, process>, buffer<bytes, 0x21>)
+        // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 0x22> name_out)
         public long OpenAudioOutAuto(ServiceCtx context)
         {
             (long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
@@ -168,4 +161,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
     }
-}
+}

+ 8 - 16
Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs

@@ -1,9 +1,7 @@
 using Ryujinx.Audio;
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -21,21 +19,11 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
         public const int RevMagic = Rev0Magic + (Rev << 24);
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAudioRendererManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, OpenAudioRenderer                     },
-                { 1, GetAudioRendererWorkBufferSize        },
-                { 2, GetAudioDeviceService                 },
-                { 4, GetAudioDeviceServiceWithRevisionInfo }
-            };
-        }
+        public IAudioRendererManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle<copy>, handle<copy>)
+        // -> object<nn::audio::detail::IAudioRenderer>
         public long OpenAudioRenderer(ServiceCtx context)
         {
             IAalOutput audioOut = context.Device.AudioOut;
@@ -51,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(1)]
+        // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64
         public long GetAudioRendererWorkBufferSize(ServiceCtx context)
         {
             AudioRendererParameter Params = GetAudioRendererParameter(context);
@@ -178,6 +168,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return result / 8;
         }
 
+        [Command(2)]
         // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
         public long GetAudioDeviceService(ServiceCtx context)
         {
@@ -188,6 +179,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(4)] // 4.0.0+
         // GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
         private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
         {

+ 16 - 24
Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoder.cs

@@ -1,6 +1,4 @@
 using Concentus.Structs;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -10,10 +8,6 @@ namespace Ryujinx.HLE.HOS.Services.Aud
     {
         private const int FixedSampleRate = 48000;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private int _sampleRate;
         private int _channelsCount;
 
@@ -21,29 +15,14 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
         public IHardwareOpusDecoder(int sampleRate, int channelsCount)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, DecodeInterleaved         },
-                { 4, DecodeInterleavedWithPerf }
-            };
-
             _sampleRate    = sampleRate;
             _channelsCount = channelsCount;
 
             _decoder = new OpusDecoder(FixedSampleRate, channelsCount);
         }
 
-        public long DecodeInterleavedWithPerf(ServiceCtx context)
-        {
-            long result = DecodeInterleaved(context);
-
-            // TODO: Figure out what this value is.
-            // According to switchbrew, it is now used.
-            context.ResponseData.Write(0L);
-
-            return result;
-        }
-
+        [Command(0)]
+        // DecodeInterleaved(buffer<unknown, 5>) -> (u32, u32, buffer<unknown, 6>)
         public long DecodeInterleaved(ServiceCtx context)
         {
             long inPosition = context.Request.SendBuff[0].Position;
@@ -87,5 +66,18 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
             return 0;
         }
+
+        [Command(4)]
+        // DecodeInterleavedWithPerf(buffer<unknown, 5>) -> (u32, u32, u64, buffer<unknown, 0x46>)
+        public long DecodeInterleavedWithPerf(ServiceCtx context)
+        {
+            long result = DecodeInterleaved(context);
+
+            // TODO: Figure out what this value is.
+            // According to switchbrew, it is now used.
+            context.ResponseData.Write(0L);
+
+            return result;
+        }
     }
-}
+}

+ 6 - 16
Ryujinx.HLE/HOS/Services/Aud/IHardwareOpusDecoderManager.cs

@@ -1,24 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Aud
 {
     [Service("hwopus")]
     class IHardwareOpusDecoderManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IHardwareOpusDecoderManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Initialize        },
-                { 1, GetWorkBufferSize }
-            };
-        }
+        public IHardwareOpusDecoderManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // Initialize(bytes<8, 4>, u32, handle<copy>) -> object<nn::codec::detail::IHardwareOpusDecoder>
         public long Initialize(ServiceCtx context)
         {
             int sampleRate    = context.RequestData.ReadInt32();
@@ -29,6 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             return 0;
         }
 
+        [Command(1)]
+        // GetWorkBufferSize(bytes<8, 4>) -> u32
         public long GetWorkBufferSize(ServiceCtx context)
         {
             // Note: The sample rate is ignored because it is fixed to 48KHz.
@@ -70,4 +60,4 @@ namespace Ryujinx.HLE.HOS.Services.Aud
                     celtSigSize;
         }
     }
-}
+}

+ 2 - 16
Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs

@@ -1,21 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Bcat
 {
     class IBcatService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IBcatService()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
-
+        public IBcatService() { }
     }
-}
+}

+ 2 - 16
Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs

@@ -1,21 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Bcat
 {
     class IDeliveryCacheStorageService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IDeliveryCacheStorageService()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
-
+        public IDeliveryCacheStorageService() { }
     }
-}
+}

+ 5 - 15
Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs

@@ -1,6 +1,3 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Bcat
 {
     [Service("bcat:a")]
@@ -9,19 +6,10 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
     [Service("bcat:s")]
     class IServiceCreator : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IServiceCreator(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, CreateBcatService                 },
-                { 1, CreateDeliveryCacheStorageService }
-            };
-        }
+        public IServiceCreator(ServiceCtx context) { }
 
+        [Command(0)]
+        // CreateBcatService(u64, pid) -> object<nn::bcat::detail::ipc::IBcatService>
         public long CreateBcatService(ServiceCtx context)
         {
             long id = context.RequestData.ReadInt64();
@@ -31,6 +19,8 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
             return 0;
         }
 
+        [Command(1)]
+        // CreateDeliveryCacheStorageService(u64, pid) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
         public long CreateDeliveryCacheStorageService(ServiceCtx context)
         {
             long id = context.RequestData.ReadInt64();

+ 30 - 41
Ryujinx.HLE/HOS/Services/Bsd/IClient.cs

@@ -1,5 +1,4 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.Utilities;
 using System.Collections.Generic;
 using System.Net;
@@ -100,52 +99,14 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
 
         private List<BsdSocket> _sockets = new List<BsdSocket>();
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IClient(ServiceCtx context, bool isPrivileged)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  RegisterClient     },
-                { 1,  StartMonitoring    },
-                { 2,  Socket             },
-                { 3,  SocketExempt       },
-                { 4,  Open               },
-                { 5,  Select             },
-                { 6,  Poll               },
-                { 7,  Sysctl             },
-                { 8,  Recv               },
-                { 9,  RecvFrom           },
-                { 10, Send               },
-                { 11, SendTo             },
-                { 12, Accept             },
-                { 13, Bind               },
-                { 14, Connect            },
-                { 15, GetPeerName        },
-                { 16, GetSockName        },
-                { 17, GetSockOpt         },
-                { 18, Listen             },
-                { 19, Ioctl              },
-                { 20, Fcntl              },
-                { 21, SetSockOpt         },
-                { 22, Shutdown           },
-                { 23, ShutdownAllSockets },
-                { 24, Write              },
-                { 25, Read               },
-                { 26, Close              },
-                { 27, DuplicateSocket    }
-            };
-
             _isPrivileged = isPrivileged;
         }
 
         private LinuxError ConvertError(WsaError errorCode)
         {
-            LinuxError errno;
-
-            if (!_errorMap.TryGetValue(errorCode, out errno))
+            if (!_errorMap.TryGetValue(errorCode, out LinuxError errno))
             {
                 errno = (LinuxError)errorCode;
             }
@@ -259,6 +220,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             WriteSockAddr(context, bufferPosition, endPoint);
         }
 
+        [Command(0)]
         // Initialize(nn::socket::BsdBufferConfig config, u64 pid, u64 transferMemorySize, KObject<copy, transfer_memory>, pid) -> u32 bsd_errno
         public long RegisterClient(ServiceCtx context)
         {
@@ -283,6 +245,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return 0;
         }
 
+        [Command(1)]
         // StartMonitoring(u64, pid)
         public long StartMonitoring(ServiceCtx context)
         {
@@ -293,18 +256,21 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return 0;
         }
 
+        [Command(2)]
         // Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
         public long Socket(ServiceCtx context)
         {
             return SocketInternal(context, false);
         }
 
+        [Command(3)]
         // SocketExempt(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
         public long SocketExempt(ServiceCtx context)
         {
             return SocketInternal(context, true);
         }
 
+        [Command(4)]
         // Open(u32 flags, array<unknown, 0x21> path) -> (i32 ret, u32 bsd_errno)
         public long Open(ServiceCtx context)
         {
@@ -322,6 +288,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return 0;
         }
 
+        [Command(5)]
         // Select(u32 nfds, nn::socket::timeout timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in) -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out)
         public long Select(ServiceCtx context)
         {
@@ -332,6 +299,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return 0;
         }
 
+        [Command(6)]
         // Poll(u32 nfds, u32 timeout, buffer<unknown, 0x21, 0> fds) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>)
         public long Poll(ServiceCtx context)
         {
@@ -457,6 +425,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, readEvents.Count + writeEvents.Count + errorEvents.Count, LinuxError.SUCCESS);
         }
 
+        [Command(7)]
         // Sysctl(buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>)
         public long Sysctl(ServiceCtx context)
         {
@@ -467,6 +436,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return 0;
         }
 
+        [Command(8)]
         // Recv(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, array<i8, 0x22> message)
         public long Recv(ServiceCtx context)
         {
@@ -506,6 +476,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(9)]
         // RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<i8, 0x22, 0> message, buffer<nn::socket::sockaddr_in, 0x22, 0x10>)
         public long RecvFrom(ServiceCtx context)
         {
@@ -550,6 +521,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(10)]
         // Send(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
         public long Send(ServiceCtx context)
         {
@@ -589,6 +561,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(11)]
         // SendTo(u32 socket, u32 flags, buffer<i8, 0x21, 0>, buffer<nn::socket::sockaddr_in, 0x21, 0x10>) -> (i32 ret, u32 bsd_errno)
         public long SendTo(ServiceCtx context)
         {
@@ -630,6 +603,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(12)]
         // Accept(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
         public long Accept(ServiceCtx context)
         {
@@ -684,6 +658,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, -1, errno);
         }
 
+        [Command(13)]
         // Bind(u32 socket, buffer<nn::socket::sockaddr_in, 0x21, 0x10> addr) -> (i32 ret, u32 bsd_errno)
         public long Bind(ServiceCtx context)
         {
@@ -713,6 +688,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(14)]
         // Connect(u32 socket, buffer<nn::socket::sockaddr_in, 0x21, 0x10>) -> (i32 ret, u32 bsd_errno)
         public long Connect(ServiceCtx context)
         {
@@ -741,6 +717,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(15)]
         // GetPeerName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
         public long GetPeerName(ServiceCtx context)
         {
@@ -763,6 +740,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(16)]
         // GetSockName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
         public long GetSockName(ServiceCtx context)
         {
@@ -785,6 +763,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(17)]
         // GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>)
         public long GetSockOpt(ServiceCtx context)
         {
@@ -814,6 +793,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(18)]
         // Listen(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno)
         public long Listen(ServiceCtx context)
         {
@@ -840,6 +820,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(19)]
         // Ioctl(u32 fd, u32 request, u32 bufcount, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>)
         public long Ioctl(ServiceCtx context)
         {
@@ -874,6 +855,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(20)]
         // Fcntl(u32 socket, u32 cmd, u32 arg) -> (i32 ret, u32 bsd_errno)
         public long Fcntl(ServiceCtx context)
         {
@@ -995,6 +977,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             }
         }
 
+        [Command(21)]
         // SetSockOpt(u32 socket, u32 level, u32 option_name, buffer<unknown, 0x21, 0> option_value) -> (i32 ret, u32 bsd_errno)
         public long SetSockOpt(ServiceCtx context)
         {
@@ -1024,6 +1007,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(22)]
         // Shutdown(u32 socket, u32 how) -> (i32 ret, u32 bsd_errno)
         public long Shutdown(ServiceCtx context)
         {
@@ -1055,6 +1039,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(23)]
         // ShutdownAllSockets(u32 how) -> (i32 ret, u32 bsd_errno)
         public long ShutdownAllSockets(ServiceCtx context)
         {
@@ -1086,6 +1071,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(24)]
         // Write(u32 socket, buffer<i8, 0x21, 0> message) -> (i32 ret, u32 bsd_errno)
         public long Write(ServiceCtx context)
         {
@@ -1115,6 +1101,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(25)]
         // Read(u32 socket) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message)
         public long Read(ServiceCtx context)
         {
@@ -1144,6 +1131,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, result, errno);
         }
 
+        [Command(26)]
         // Close(u32 socket) -> (i32 ret, u32 bsd_errno)
         public long Close(ServiceCtx context)
         {
@@ -1164,6 +1152,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, 0, errno);
         }
 
+        [Command(27)]
         // DuplicateSocket(u32 socket, u64 reserved) -> (i32 ret, u32 bsd_errno)
         public long DuplicateSocket(ServiceCtx context)
         {
@@ -1189,4 +1178,4 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
             return WriteBsdResult(context, newSockFd, errno);
         }
     }
-}
+}

+ 1 - 14
Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Caps
 {
     [Service("caps:a")]
     class IAlbumAccessorService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAlbumAccessorService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IAlbumAccessorService(ServiceCtx context) { }
     }
 }

+ 1 - 14
Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Caps
 {
     [Service("caps:ss")]
     class IScreenshotService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IScreenshotService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IScreenshotService(ServiceCtx context) { }
     }
 }

+ 12 - 0
Ryujinx.HLE/HOS/Services/CommandAttributes.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.HLE.HOS.Services
+{
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    public class CommandAttribute : Attribute
+    {
+        public readonly int Id;
+
+        public CommandAttribute(int id) => Id = id;
+    }
+}

+ 2 - 10
Ryujinx.HLE/HOS/Services/DummyService.cs

@@ -1,20 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services
+namespace Ryujinx.HLE.HOS.Services
 {
     class DummyService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public string ServiceName { get; set; }
 
         public DummyService(string serviceName)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>();
             ServiceName = serviceName;
         }
     }
-}
+}

+ 2 - 15
Ryujinx.HLE/HOS/Services/Es/IETicketService.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Es
+namespace Ryujinx.HLE.HOS.Services.Es
 {
     [Service("es")]
     class IeTicketService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IeTicketService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                //...
-            };
-        }
+        public IeTicketService(ServiceCtx context) { }
     }
 }

+ 0 - 16
Ryujinx.HLE/HOS/Services/Friend/IDaemonSuspendSessionService.cs

@@ -1,27 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Friend
 {
     class IDaemonSuspendSessionService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
         private FriendServicePermissionLevel PermissionLevel;
 
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                //{ 0, Unknown0 }, // 4.0.0+
-                //{ 1, Unknown1 }, // 4.0.0+
-                //{ 2, Unknown2 }, // 4.0.0+
-                //{ 3, Unknown3 }, // 4.0.0+
-                //{ 4, Unknown4 }, // 4.0.0+
-            };
-
             PermissionLevel = permissionLevel;
         }
     }

+ 10 - 86
Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs

@@ -1,9 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 using System.IO;
 using System.Runtime.InteropServices;
 
@@ -13,95 +11,16 @@ namespace Ryujinx.HLE.HOS.Services.Friend
 {
     class IFriendService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
         private FriendServicePermissionLevel _permissionLevel;
 
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IFriendService(FriendServicePermissionLevel permissionLevel)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-              //{ 0,     GetCompletionEvent                                       },
-              //{ 1,     Cancel                                                   },
-                { 10100, GetFriendListIds                                         },
-                { 10101, GetFriendList                                            },
-              //{ 10102, UpdateFriendInfo                                         },
-              //{ 10110, GetFriendProfileImage                                    },
-              //{ 10200, SendFriendRequestForApplication                          },
-              //{ 10211, AddFacedFriendRequestForApplication                      },
-              //{ 10400, GetBlockedUserListIds                                    },
-              //{ 10500, GetProfileList                                           },
-                { 10600, DeclareOpenOnlinePlaySession                             },
-                { 10601, DeclareCloseOnlinePlaySession                            },
-                { 10610, UpdateUserPresence                                       },
-              //{ 10700, GetPlayHistoryRegistrationKey                            },
-              //{ 10701, GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId },
-              //{ 10702, AddPlayHistory                                           },
-              //{ 11000, GetProfileImageUrl                                       },
-              //{ 20100, GetFriendCount                                           },
-              //{ 20101, GetNewlyFriendCount                                      },
-              //{ 20102, GetFriendDetailedInfo                                    },
-              //{ 20103, SyncFriendList                                           },
-              //{ 20104, RequestSyncFriendList                                    },
-              //{ 20110, LoadFriendSetting                                        },
-              //{ 20200, GetReceivedFriendRequestCount                            },
-              //{ 20201, GetFriendRequestList                                     },
-              //{ 20300, GetFriendCandidateList                                   },
-              //{ 20301, GetNintendoNetworkIdInfo                                 }, // 3.0.0+
-              //{ 20302, GetSnsAccountLinkage                                     }, // 5.0.0+
-              //{ 20303, GetSnsAccountProfile                                     }, // 5.0.0+
-              //{ 20304, GetSnsAccountFriendList                                  }, // 5.0.0+
-              //{ 20400, GetBlockedUserList                                       },
-              //{ 20401, SyncBlockedUserList                                      },
-              //{ 20500, GetProfileExtraList                                      },
-              //{ 20501, GetRelationship                                          },
-              //{ 20600, GetUserPresenceView                                      },
-              //{ 20700, GetPlayHistoryList                                       },
-              //{ 20701, GetPlayHistoryStatistics                                 },
-              //{ 20800, LoadUserSetting                                          },
-              //{ 20801, SyncUserSetting                                          },
-              //{ 20900, RequestListSummaryOverlayNotification                    },
-              //{ 21000, GetExternalApplicationCatalog                            },
-              //{ 30100, DropFriendNewlyFlags                                     },
-              //{ 30101, DeleteFriend                                             },
-              //{ 30110, DropFriendNewlyFlag                                      },
-              //{ 30120, ChangeFriendFavoriteFlag                                 },
-              //{ 30121, ChangeFriendOnlineNotificationFlag                       },
-              //{ 30200, SendFriendRequest                                        },
-              //{ 30201, SendFriendRequestWithApplicationInfo                     },
-              //{ 30202, CancelFriendRequest                                      },
-              //{ 30203, AcceptFriendRequest                                      },
-              //{ 30204, RejectFriendRequest                                      },
-              //{ 30205, ReadFriendRequest                                        },
-              //{ 30210, GetFacedFriendRequestRegistrationKey                     },
-              //{ 30211, AddFacedFriendRequest                                    },
-              //{ 30212, CancelFacedFriendRequest                                 },
-              //{ 30213, GetFacedFriendRequestProfileImage                        },
-              //{ 30214, GetFacedFriendRequestProfileImageFromPath                },
-              //{ 30215, SendFriendRequestWithExternalApplicationCatalogId        },
-              //{ 30216, ResendFacedFriendRequest                                 },
-              //{ 30217, SendFriendRequestWithNintendoNetworkIdInfo               }, // 3.0.0+
-              //{ 30300, GetSnsAccountLinkPageUrl                                 }, // 5.0.0+
-              //{ 30301, UnlinkSnsAccount                                         }, // 5.0.0+
-              //{ 30400, BlockUser                                                },
-              //{ 30401, BlockUserWithApplicationInfo                             },
-              //{ 30402, UnblockUser                                              },
-              //{ 30500, GetProfileExtraFromFriendCode                            },
-              //{ 30700, DeletePlayHistory                                        },
-              //{ 30810, ChangePresencePermission                                 },
-              //{ 30811, ChangeFriendRequestReception                             },
-              //{ 30812, ChangePlayLogPermission                                  },
-              //{ 30820, IssueFriendCode                                          },
-              //{ 30830, ClearPlayLog                                             },
-              //{ 49900, DeleteNetworkServiceAccountCache                         },
-            };
-
             _permissionLevel = permissionLevel;
         }
 
-        // nn::friends::GetFriendListIds(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) -> int outCount, array<nn::account::NetworkServiceAccountId, 0xa>
+        [Command(10100)]
+        // nn::friends::GetFriendListIds(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) 
+        // -> int outCount, array<nn::account::NetworkServiceAccountId, 0xa>
         public long GetFriendListIds(ServiceCtx context)
         {
             int offset = context.RequestData.ReadInt32();
@@ -138,7 +57,9 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
-        // nn::friends::GetFriendList(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) -> int outCount, array<nn::friends::detail::FriendImpl, 0x6>
+        [Command(10101)]
+        // nn::friends::GetFriendList(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) 
+        // -> int outCount, array<nn::friends::detail::FriendImpl, 0x6>
         public long GetFriendList(ServiceCtx context)
         {
             int offset = context.RequestData.ReadInt32();
@@ -174,6 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(10600)]
         // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid)
         public long DeclareOpenOnlinePlaySession(ServiceCtx context)
         {
@@ -194,6 +116,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(10601)]
         // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid)
         public long DeclareCloseOnlinePlaySession(ServiceCtx context)
         {
@@ -214,6 +137,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(10610)]
         // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer<nn::friends::detail::UserPresenceImpl, 0x19>)
         public long UpdateUserPresence(ServiceCtx context)
         {
@@ -244,4 +168,4 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
     }
-}
+}

+ 3 - 12
Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs

@@ -20,25 +20,13 @@ namespace Ryujinx.HLE.HOS.Services.Friend
         private KEvent _notificationEvent;
         private int    _notificationEventHandle = 0;
 
-
         private LinkedList<NotificationInfo> _notifications;
 
         private bool _hasNewFriendRequest;
         private bool _hasFriendListUpdate;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public INotificationService(ServiceCtx context, UInt128 userId, FriendServicePermissionLevel permissionLevel)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetEvent }, // 2.0.0+
-                { 1, Clear    }, // 2.0.0+
-                { 2, Pop      }, // 2.0.0+
-            };
-
             _userId            = userId;
             _permissionLevel   = permissionLevel;
             _notifications     = new LinkedList<NotificationInfo>();
@@ -50,6 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             NotificationEventHandler.Instance.RegisterNotificationService(this);
         }
 
+        [Command(0)] //2.0.0+
         // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle<copy>
         public long GetEvent(ServiceCtx context)
         {
@@ -66,6 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(1)] //2.0.0+
         // nn::friends::detail::ipc::INotificationService::Clear()
         public long Clear(ServiceCtx context)
         {
@@ -80,6 +70,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(2)] // 2.0.0+
         // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo
         public long Pop(ServiceCtx context)
         {

+ 4 - 14
Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs

@@ -1,7 +1,5 @@
 using Ryujinx.Common;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -16,22 +14,12 @@ namespace Ryujinx.HLE.HOS.Services.Friend
     {
         private FriendServicePermissionLevel _permissionLevel;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IServiceCreator(ServiceCtx context, FriendServicePermissionLevel permissionLevel)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, CreateFriendService               },
-                { 1, CreateNotificationService         }, // 2.0.0+
-                { 2, CreateDaemonSuspendSessionService }, // 4.0.0+
-            };
-
             _permissionLevel = permissionLevel;
         }
 
+        [Command(0)]
         // CreateFriendService() -> object<nn::friends::detail::ipc::IFriendService>
         public long CreateFriendService(ServiceCtx context)
         {
@@ -40,6 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(1)] // 2.0.0+
         // CreateNotificationService(nn::account::Uid) -> object<nn::friends::detail::ipc::INotificationService>
         public long CreateNotificationService(ServiceCtx context)
         {
@@ -55,6 +44,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
 
+        [Command(2)] // 4.0.0+
         // CreateDaemonSuspendSessionService() -> object<nn::friends::detail::ipc::IDaemonSuspendSessionService>
         public long CreateDaemonSuspendSessionService(ServiceCtx context)
         {
@@ -63,4 +53,4 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
     }
-}
+}

+ 3 - 13
Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs

@@ -1,5 +1,4 @@
 using LibHac;
-using Ryujinx.HLE.HOS.Ipc;
 using System.Collections.Generic;
 using System.Text;
 
@@ -9,27 +8,17 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
     {
         private const int DirectoryEntrySize = 0x310;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private IEnumerator<LibHac.Fs.DirectoryEntry> _enumerator;
 
         private LibHac.Fs.IDirectory _baseDirectory;
 
         public IDirectory(LibHac.Fs.IDirectory directory)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Read          },
-                { 1, GetEntryCount }
-            };
-
             _baseDirectory = directory;
-
-            _enumerator = directory.Read().GetEnumerator();
+            _enumerator    = directory.Read().GetEnumerator();
         }
 
+        [Command(0)]
         // Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
         public long Read(ServiceCtx context)
         {
@@ -76,6 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             context.Memory.WriteInt64(position + 0x308, entry.Size);
         }
 
+        [Command(1)]
         // GetEntryCount() -> u64
         public long GetEntryCount(ServiceCtx context)
         {

+ 5 - 15
Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs

@@ -1,33 +1,19 @@
 using LibHac;
 using LibHac.Fs;
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.FspSrv
 {
     class IFile : IpcService, IDisposable
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private LibHac.Fs.IFile _baseFile;
 
         public IFile(LibHac.Fs.IFile baseFile)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Read    },
-                { 1, Write   },
-                { 2, Flush   },
-                { 3, SetSize },
-                { 4, GetSize }
-            };
-
             _baseFile = baseFile;
         }
 
+        [Command(0)]
         // Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
         public long Read(ServiceCtx context)
         {
@@ -58,6 +44,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(1)]
         // Write(u32 writeOption, u64 offset, u64 size, buffer<u8, 0x45, 0>)
         public long Write(ServiceCtx context)
         {
@@ -83,6 +70,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(2)]
         // Flush()
         public long Flush(ServiceCtx context)
         {
@@ -98,6 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(3)]
         // SetSize(u64 size)
         public long SetSize(ServiceCtx context)
         {
@@ -115,6 +104,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(4)]
         // GetSize() -> u64 fileSize
         public long GetSize(ServiceCtx context)
         {

+ 15 - 25
Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs

@@ -1,7 +1,5 @@
 using LibHac;
 using LibHac.Fs;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 using static Ryujinx.HLE.Utilities.StringUtils;
@@ -10,36 +8,14 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
 {
     class IFileSystem : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private LibHac.Fs.IFileSystem _fileSystem;
 
         public IFileSystem(LibHac.Fs.IFileSystem provider)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  CreateFile                 },
-                { 1,  DeleteFile                 },
-                { 2,  CreateDirectory            },
-                { 3,  DeleteDirectory            },
-                { 4,  DeleteDirectoryRecursively },
-                { 5,  RenameFile                 },
-                { 6,  RenameDirectory            },
-                { 7,  GetEntryType               },
-                { 8,  OpenFile                   },
-                { 9,  OpenDirectory              },
-                { 10, Commit                     },
-                { 11, GetFreeSpaceSize           },
-                { 12, GetTotalSpaceSize          },
-                { 13, CleanDirectoryRecursively  },
-                { 14, GetFileTimeStampRaw        }
-            };
-
             _fileSystem = provider;
         }
 
+        [Command(0)]
         // CreateFile(u32 createOption, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path)
         public long CreateFile(ServiceCtx context)
         {
@@ -62,6 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(1)]
         // DeleteFile(buffer<bytes<0x301>, 0x19, 0x301> path)
         public long DeleteFile(ServiceCtx context)
         {
@@ -79,6 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(2)]
         // CreateDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
         public long CreateDirectory(ServiceCtx context)
         {
@@ -96,6 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(3)]
         // DeleteDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
         public long DeleteDirectory(ServiceCtx context)
         {
@@ -113,6 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(4)]
         // DeleteDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
         public long DeleteDirectoryRecursively(ServiceCtx context)
         {
@@ -130,6 +110,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(5)]
         // RenameFile(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
         public long RenameFile(ServiceCtx context)
         {
@@ -148,6 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(6)]
         // RenameDirectory(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
         public long RenameDirectory(ServiceCtx context)
         {
@@ -166,6 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(7)]
         // GetEntryType(buffer<bytes<0x301>, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType
         public long GetEntryType(ServiceCtx context)
         {
@@ -192,6 +175,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(8)]
         // OpenFile(u32 mode, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IFile> file
         public long OpenFile(ServiceCtx context)
         {
@@ -215,6 +199,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(9)]
         // OpenDirectory(u32 filter_flags, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IDirectory> directory
         public long OpenDirectory(ServiceCtx context)
         {
@@ -238,6 +223,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(10)]
         // Commit()
         public long Commit(ServiceCtx context)
         {
@@ -253,6 +239,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(11)]
         // GetFreeSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalFreeSpace
         public long GetFreeSpaceSize(ServiceCtx context)
         {
@@ -270,6 +257,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(12)]
         // GetTotalSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalSize
         public long GetTotalSpaceSize(ServiceCtx context)
         {
@@ -287,6 +275,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(13)]
         // CleanDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
         public long CleanDirectoryRecursively(ServiceCtx context)
         {
@@ -304,6 +293,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(14)]
         // GetFileTimeStampRaw(buffer<bytes<0x301>, 0x19, 0x301> path) -> bytes<0x20> timestamp
         public long GetFileTimeStampRaw(ServiceCtx context)
         {

+ 12 - 23
Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs

@@ -4,9 +4,7 @@ using LibHac.Fs.NcaUtils;
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.Utilities;
-using System.Collections.Generic;
 using System.IO;
 
 using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
@@ -18,34 +16,16 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
     [Service("fsp-srv")]
     class IFileSystemProxy : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IFileSystemProxy(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 1,    Initialize                               },
-                { 8,    OpenFileSystemWithId                     },
-                { 11,   OpenBisFileSystem                        },
-                { 18,   OpenSdCardFileSystem                     },
-                { 51,   OpenSaveDataFileSystem                   },
-                { 52,   OpenSaveDataFileSystemBySystemSaveDataId },
-                { 200,  OpenDataStorageByCurrentProcess          },
-                { 202,  OpenDataStorageByDataId                  },
-                { 203,  OpenPatchDataStorageByCurrentProcess     },
-                { 1005, GetGlobalAccessLogMode                   },
-                { 1006, OutputAccessLogToSdCard                  }
-            };
-        }
+        public IFileSystemProxy(ServiceCtx context) { }
 
+        [Command(1)]
         // Initialize(u64, pid)
         public long Initialize(ServiceCtx context)
         {
             return 0;
         }
 
+        [Command(8)]
         // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path) 
         // -> object<nn::fssrv::sf::IFileSystem> contentFs
         public long OpenFileSystemWithId(ServiceCtx context)
@@ -80,6 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return MakeError(ErrorModule.Fs, FsErr.InvalidInput);
         }
 
+        [Command(11)]
         // OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer<bytes<0x301>, 0x19, 0x301>) -> object<nn::fssrv::sf::IFileSystem> Bis
         public long OpenBisFileSystem(ServiceCtx context)
         {
@@ -112,6 +93,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(18)]
         // OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem>
         public long OpenSdCardFileSystem(ServiceCtx context)
         {
@@ -124,18 +106,21 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(51)]
         // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
         public long OpenSaveDataFileSystem(ServiceCtx context)
         {
             return LoadSaveDataFileSystem(context);
         }
 
+        [Command(52)]
         // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs
         public long OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context)
         {
             return LoadSaveDataFileSystem(context);
         }
 
+        [Command(200)]
         // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
         public long OpenDataStorageByCurrentProcess(ServiceCtx context)
         {
@@ -144,6 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(202)]
         // OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage
         public long OpenDataStorageByDataId(ServiceCtx context)
         {
@@ -204,6 +190,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             throw new FileNotFoundException($"System archive with titleid {titleId:x16} was not found on Storage {storageId}. Found in {installedStorage}.");
         }
 
+        [Command(203)]
         // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
         public long OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
         {
@@ -212,6 +199,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(1005)]
         // GetGlobalAccessLogMode() -> u32 logMode
         public long GetGlobalAccessLogMode(ServiceCtx context)
         {
@@ -222,6 +210,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(1006)]
         // OutputAccessLogToSdCard(buffer<bytes, 5> log_text)
         public long OutputAccessLogToSdCard(ServiceCtx context)
         {

+ 3 - 12
Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs

@@ -1,28 +1,18 @@
 using LibHac;
 using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.FspSrv
 {
     class IStorage : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private LibHac.Fs.IStorage _baseStorage;
 
         public IStorage(LibHac.Fs.IStorage baseStorage)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Read    },
-                { 4, GetSize }
-            };
-
             _baseStorage = baseStorage;
         }
 
+        [Command(0)]
         // Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
         public long Read(ServiceCtx context)
         {
@@ -56,6 +46,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
 
+        [Command(4)]
         // GetSize() -> u64 size
         public long GetSize(ServiceCtx context)
         {
@@ -71,4 +62,4 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
             return 0;
         }
     }
-}
+}

+ 3 - 14
Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs

@@ -1,22 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Hid
 {
     class IActiveApplicationDeviceList : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IActiveApplicationDeviceList()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, ActivateVibrationDevice }
-            };
-        }
+        public IActiveApplicationDeviceList() { }
 
+        [Command(0)]
+        // ActivateVibrationDevice(nn::hid::VibrationDeviceHandle)
         public long ActivateVibrationDevice(ServiceCtx context)
         {
             int vibrationDeviceHandle = context.RequestData.ReadInt32();

+ 2 - 10
Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs

@@ -2,28 +2,20 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Memory;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Hid
 {
     class IAppletResource : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KSharedMemory _hidSharedMem;
 
         public IAppletResource(KSharedMemory hidSharedMem)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetSharedMemoryHandle }
-            };
-
             _hidSharedMem = hidSharedMem;
         }
 
+        [Command(0)]
+        // GetSharedMemoryHandle() -> handle<copy>
         public long GetSharedMemoryHandle(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success)

+ 102 - 125
Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs

@@ -4,15 +4,12 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.Input;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Hid
 {
     [Service("hid")]
     class IHidServer : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
         private KEvent _npadStyleSetUpdateEvent;
         private KEvent _xpadIdEvent;
         private KEvent _palmaOperationCompleteEvent;
@@ -39,117 +36,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         private HidAccelerometerParameters _accelerometerParams;
         private HidVibrationValue          _vibrationValue;
 
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         public IHidServer(ServiceCtx context)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,    CreateAppletResource                          },
-                { 1,    ActivateDebugPad                              },
-                { 11,   ActivateTouchScreen                           },
-                { 21,   ActivateMouse                                 },
-                { 31,   ActivateKeyboard                              },
-                { 40,   AcquireXpadIdEventHandle                      },
-                { 41,   ReleaseXpadIdEventHandle                      },
-                { 51,   ActivateXpad                                  },
-                { 55,   GetXpadIds                                    },
-                { 56,   ActivateJoyXpad                               },
-                { 58,   GetJoyXpadLifoHandle                          },
-                { 59,   GetJoyXpadIds                                 },
-                { 60,   ActivateSixAxisSensor                         },
-                { 61,   DeactivateSixAxisSensor                       },
-                { 62,   GetSixAxisSensorLifoHandle                    },
-                { 63,   ActivateJoySixAxisSensor                      },
-                { 64,   DeactivateJoySixAxisSensor                    },
-                { 65,   GetJoySixAxisSensorLifoHandle                 },
-                { 66,   StartSixAxisSensor                            },
-                { 67,   StopSixAxisSensor                             },
-                { 68,   IsSixAxisSensorFusionEnabled                  },
-                { 69,   EnableSixAxisSensorFusion                     },
-                { 70,   SetSixAxisSensorFusionParameters              },
-                { 71,   GetSixAxisSensorFusionParameters              },
-                { 72,   ResetSixAxisSensorFusionParameters            },
-                { 73,   SetAccelerometerParameters                    },
-                { 74,   GetAccelerometerParameters                    },
-                { 75,   ResetAccelerometerParameters                  },
-                { 76,   SetAccelerometerPlayMode                      },
-                { 77,   GetAccelerometerPlayMode                      },
-                { 78,   ResetAccelerometerPlayMode                    },
-                { 79,   SetGyroscopeZeroDriftMode                     },
-                { 80,   GetGyroscopeZeroDriftMode                     },
-                { 81,   ResetGyroscopeZeroDriftMode                   },
-                { 82,   IsSixAxisSensorAtRest                         },
-                { 91,   ActivateGesture                               },
-                { 100,  SetSupportedNpadStyleSet                      },
-                { 101,  GetSupportedNpadStyleSet                      },
-                { 102,  SetSupportedNpadIdType                        },
-                { 103,  ActivateNpad                                  },
-                { 104,  DeactivateNpad                                },
-                { 106,  AcquireNpadStyleSetUpdateEventHandle          },
-                { 107,  DisconnectNpad                                },
-                { 108,  GetPlayerLedPattern                           },
-                { 109,  ActivateNpadWithRevision                      },
-                { 120,  SetNpadJoyHoldType                            },
-                { 121,  GetNpadJoyHoldType                            },
-                { 122,  SetNpadJoyAssignmentModeSingleByDefault       },
-                { 123,  SetNpadJoyAssignmentModeSingle                },
-                { 124,  SetNpadJoyAssignmentModeDual                  },
-                { 125,  MergeSingleJoyAsDualJoy                       },
-                { 126,  StartLrAssignmentMode                         },
-                { 127,  StopLrAssignmentMode                          },
-                { 128,  SetNpadHandheldActivationMode                 },
-                { 129,  GetNpadHandheldActivationMode                 },
-                { 130,  SwapNpadAssignment                            },
-                { 131,  IsUnintendedHomeButtonInputProtectionEnabled  },
-                { 132,  EnableUnintendedHomeButtonInputProtection     },
-                { 133,  SetNpadJoyAssignmentModeSingleWithDestination },
-                { 200,  GetVibrationDeviceInfo                        },
-                { 201,  SendVibrationValue                            },
-                { 202,  GetActualVibrationValue                       },
-                { 203,  CreateActiveVibrationDeviceList               },
-                { 204,  PermitVibration                               },
-                { 205,  IsVibrationPermitted                          },
-                { 206,  SendVibrationValues                           },
-                { 207,  SendVibrationGcErmCommand                     },
-                { 208,  GetActualVibrationGcErmCommand                },
-                { 209,  BeginPermitVibrationSession                   },
-                { 210,  EndPermitVibrationSession                     },
-                { 300,  ActivateConsoleSixAxisSensor                  },
-                { 301,  StartConsoleSixAxisSensor                     },
-                { 302,  StopConsoleSixAxisSensor                      },
-                { 303,  ActivateSevenSixAxisSensor                    },
-                { 304,  StartSevenSixAxisSensor                       },
-                { 305,  StopSevenSixAxisSensor                        },
-                { 306,  InitializeSevenSixAxisSensor                  },
-                { 307,  FinalizeSevenSixAxisSensor                    },
-                { 308,  SetSevenSixAxisSensorFusionStrength           },
-                { 309,  GetSevenSixAxisSensorFusionStrength           },
-                { 400,  IsUsbFullKeyControllerEnabled                 },
-                { 401,  EnableUsbFullKeyController                    },
-                { 402,  IsUsbFullKeyControllerConnected               },
-                { 403,  HasBattery                                    },
-                { 404,  HasLeftRightBattery                           },
-                { 405,  GetNpadInterfaceType                          },
-                { 406,  GetNpadLeftRightInterfaceType                 },
-                { 500,  GetPalmaConnectionHandle                      },
-                { 501,  InitializePalma                               },
-                { 502,  AcquirePalmaOperationCompleteEvent            },
-                { 503,  GetPalmaOperationInfo                         },
-                { 504,  PlayPalmaActivity                             },
-                { 505,  SetPalmaFrModeType                            },
-                { 506,  ReadPalmaStep                                 },
-                { 507,  EnablePalmaStep                               },
-                { 508,  SuspendPalmaStep                              },
-                { 509,  ResetPalmaStep                                },
-                { 510,  ReadPalmaApplicationSection                   },
-                { 511,  WritePalmaApplicationSection                  },
-                { 512,  ReadPalmaUniqueCode                           },
-                { 513,  SetPalmaUniqueCodeInvalid                     },
-                { 1000, SetNpadCommunicationMode                      },
-                { 1001, GetNpadCommunicationMode                      }
-            };
-
             _npadStyleSetUpdateEvent     = new KEvent(context.Device.System);
             _xpadIdEvent                 = new KEvent(context.Device.System);
             _palmaOperationCompleteEvent = new KEvent(context.Device.System);
@@ -168,6 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             _xpadIdEvent.ReadableEvent.Signal();
         }
 
+        [Command(0)]
         // CreateAppletResource(nn::applet::AppletResourceUserId) -> object<nn::hid::IAppletResource>
         public long CreateAppletResource(ServiceCtx context)
         {
@@ -178,6 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(1)]
         // ActivateDebugPad(nn::applet::AppletResourceUserId)
         public long ActivateDebugPad(ServiceCtx context)
         {
@@ -188,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(11)]
         // ActivateTouchScreen(nn::applet::AppletResourceUserId)
         public long ActivateTouchScreen(ServiceCtx context)
         {
@@ -198,6 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(21)]
         // ActivateMouse(nn::applet::AppletResourceUserId)
         public long ActivateMouse(ServiceCtx context)
         {
@@ -208,6 +100,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(31)]
         // ActivateKeyboard(nn::applet::AppletResourceUserId)
         public long ActivateKeyboard(ServiceCtx context)
         {
@@ -218,6 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(40)]
         // AcquireXpadIdEventHandle(ulong XpadId) -> nn::sf::NativeHandle
         public long AcquireXpadIdEventHandle(ServiceCtx context)
         {
@@ -235,6 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(41)]
         // ReleaseXpadIdEventHandle(ulong XpadId)
         public long ReleaseXpadIdEventHandle(ServiceCtx context)
         {
@@ -247,6 +142,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(51)]
         // ActivateXpad(nn::hid::BasicXpadId, nn::applet::AppletResourceUserId)
         public long ActivateXpad(ServiceCtx context)
         {
@@ -258,6 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(55)]
         // GetXpadIds() -> long IdsCount, buffer<array<nn::hid::BasicXpadId>, type: 0xa>
         public long GetXpadIds(ServiceCtx context)
         {
@@ -269,6 +166,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(56)]
         // ActivateJoyXpad(nn::hid::JoyXpadId)
         public long ActivateJoyXpad(ServiceCtx context)
         {
@@ -279,6 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(58)]
         // GetJoyXpadLifoHandle(nn::hid::JoyXpadId) -> nn::sf::NativeHandle
         public long GetJoyXpadLifoHandle(ServiceCtx context)
         {
@@ -293,6 +192,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(59)]
         // GetJoyXpadIds() -> long IdsCount, buffer<array<nn::hid::JoyXpadId>, type: 0xa>
         public long GetJoyXpadIds(ServiceCtx context)
         {
@@ -304,6 +204,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(60)]
         // ActivateSixAxisSensor(nn::hid::BasicXpadId)
         public long ActivateSixAxisSensor(ServiceCtx context)
         {
@@ -314,6 +215,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(61)]
         // DeactivateSixAxisSensor(nn::hid::BasicXpadId)
         public long DeactivateSixAxisSensor(ServiceCtx context)
         {
@@ -324,6 +226,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(62)]
         // GetSixAxisSensorLifoHandle(nn::hid::BasicXpadId) -> nn::sf::NativeHandle
         public long GetSixAxisSensorLifoHandle(ServiceCtx context)
         {
@@ -338,6 +241,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(63)]
         // ActivateJoySixAxisSensor(nn::hid::JoyXpadId)
         public long ActivateJoySixAxisSensor(ServiceCtx context)
         {
@@ -348,6 +252,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(64)]
         // DeactivateJoySixAxisSensor(nn::hid::JoyXpadId)
         public long DeactivateJoySixAxisSensor(ServiceCtx context)
         {
@@ -358,6 +263,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(65)]
         // GetJoySixAxisSensorLifoHandle(nn::hid::JoyXpadId) -> nn::sf::NativeHandle
         public long GetJoySixAxisSensorLifoHandle(ServiceCtx context)
         {
@@ -372,6 +278,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(66)]
         // StartSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long StartSixAxisSensor(ServiceCtx context)
         {
@@ -383,6 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(67)]
         // StopSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long StopSixAxisSensor(ServiceCtx context)
         {
@@ -394,6 +302,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(68)]
         // IsSixAxisSensorFusionEnabled(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsEnabled
         public long IsSixAxisSensorFusionEnabled(ServiceCtx context)
         {
@@ -407,6 +316,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(69)]
         // EnableSixAxisSensorFusion(bool Enabled, nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long EnableSixAxisSensorFusion(ServiceCtx context)
         {
@@ -419,6 +329,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(70)]
         // SetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, float RevisePower, float ReviseRange, nn::applet::AppletResourceUserId)
         public long SetSixAxisSensorFusionParameters(ServiceCtx context)
         {
@@ -437,6 +348,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(71)]
         // GetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float RevisePower, float ReviseRange)
         public long GetSixAxisSensorFusionParameters(ServiceCtx context)
         {
@@ -451,6 +363,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(72)]
         // ResetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long ResetSixAxisSensorFusionParameters(ServiceCtx context)
         {
@@ -465,6 +378,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(73)]
         // SetAccelerometerParameters(nn::hid::SixAxisSensorHandle, float X, float Y, nn::applet::AppletResourceUserId)
         public long SetAccelerometerParameters(ServiceCtx context)
         {
@@ -483,6 +397,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(74)]
         // GetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float X, float Y
         public long GetAccelerometerParameters(ServiceCtx context)
         {
@@ -497,6 +412,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(75)]
         // ResetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long ResetAccelerometerParameters(ServiceCtx context)
         {
@@ -511,6 +427,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(76)]
         // SetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, uint PlayMode, nn::applet::AppletResourceUserId)
         public long SetAccelerometerPlayMode(ServiceCtx context)
         {
@@ -523,6 +440,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(77)]
         // GetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> uint PlayMode
         public long GetAccelerometerPlayMode(ServiceCtx context)
         {
@@ -536,6 +454,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(78)]
         // ResetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long ResetAccelerometerPlayMode(ServiceCtx context)
         {
@@ -549,6 +468,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(79)]
         // SetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, uint GyroscopeZeroDriftMode, nn::applet::AppletResourceUserId)
         public long SetGyroscopeZeroDriftMode(ServiceCtx context)
         {
@@ -561,6 +481,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(80)]
         // GetGyroscopeZeroDriftMode(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle) -> int GyroscopeZeroDriftMode
         public long GetGyroscopeZeroDriftMode(ServiceCtx context)
         {
@@ -574,6 +495,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(81)]
         // ResetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long ResetGyroscopeZeroDriftMode(ServiceCtx context)
         {
@@ -587,6 +509,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(82)]
         // IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest
         public long IsSixAxisSensorAtRest(ServiceCtx context)
         {
@@ -602,6 +525,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(91)]
         // ActivateGesture(nn::applet::AppletResourceUserId, int Unknown0)
         public long ActivateGesture(ServiceCtx context)
         {
@@ -613,7 +537,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
-
+        [Command(100)]
         // SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
         public long SetSupportedNpadStyleSet(ServiceCtx context)
         {
@@ -628,6 +552,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(101)]
         // GetSupportedNpadStyleSet(nn::applet::AppletResourceUserId) -> uint nn::hid::NpadStyleTag
         public long GetSupportedNpadStyleSet(ServiceCtx context)
         {
@@ -640,6 +565,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(102)]
         // SetSupportedNpadIdType(nn::applet::AppletResourceUserId, array<NpadIdType, 9>)
         public long SetSupportedNpadIdType(ServiceCtx context)
         {
@@ -651,6 +577,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(103)]
         // ActivateNpad(nn::applet::AppletResourceUserId)
         public long ActivateNpad(ServiceCtx context)
         {
@@ -661,6 +588,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(104)]
         // DeactivateNpad(nn::applet::AppletResourceUserId)
         public long DeactivateNpad(ServiceCtx context)
         {
@@ -671,6 +599,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(106)]
         // AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle
         public long AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context)
         {
@@ -690,6 +619,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(107)]
         // DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType)
         public long DisconnectNpad(ServiceCtx context)
         {
@@ -701,6 +631,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(108)]
         // GetPlayerLedPattern(uint NpadId) -> ulong LedPattern
         public long GetPlayerLedPattern(ServiceCtx context)
         {
@@ -715,6 +646,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(109)] // 5.0.0+
         // ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown)
         public long ActivateNpadWithRevision(ServiceCtx context)
         {
@@ -726,6 +658,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(120)]
         // SetNpadJoyHoldType(nn::applet::AppletResourceUserId, long NpadJoyHoldType)
         public long SetNpadJoyHoldType(ServiceCtx context)
         {
@@ -737,6 +670,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(121)]
         // GetNpadJoyHoldType(nn::applet::AppletResourceUserId) -> long NpadJoyHoldType
         public long GetNpadJoyHoldType(ServiceCtx context)
         {
@@ -749,6 +683,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(122)]
         // SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
         public long SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
         {
@@ -762,6 +697,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(123)]
         // SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
         public long SetNpadJoyAssignmentModeSingle(ServiceCtx context)
         {
@@ -776,6 +712,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(124)]
         // SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId)
         public long SetNpadJoyAssignmentModeDual(ServiceCtx context)
         {
@@ -789,6 +726,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(125)]
         // MergeSingleJoyAsDualJoy(uint SingleJoyId0, uint SingleJoyId1, nn::applet::AppletResourceUserId)
         public long MergeSingleJoyAsDualJoy(ServiceCtx context)
         {
@@ -801,6 +739,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(126)]
         // StartLrAssignmentMode(nn::applet::AppletResourceUserId)
         public long StartLrAssignmentMode(ServiceCtx context)
         {
@@ -811,6 +750,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(127)]
         // StopLrAssignmentMode(nn::applet::AppletResourceUserId)
         public long StopLrAssignmentMode(ServiceCtx context)
         {
@@ -821,6 +761,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(128)]
         // SetNpadHandheldActivationMode(nn::applet::AppletResourceUserId, long HidNpadHandheldActivationMode)
         public long SetNpadHandheldActivationMode(ServiceCtx context)
         {
@@ -832,6 +773,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(129)]
         // GetNpadHandheldActivationMode(nn::applet::AppletResourceUserId) -> long HidNpadHandheldActivationMode
         public long GetNpadHandheldActivationMode(ServiceCtx context)
         {
@@ -844,6 +786,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(130)]
         // SwapNpadAssignment(uint OldNpadAssignment, uint NewNpadAssignment, nn::applet::AppletResourceUserId)
         public long SwapNpadAssignment(ServiceCtx context)
         {
@@ -856,6 +799,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(131)]
         // IsUnintendedHomeButtonInputProtectionEnabled(uint Unknown0, nn::applet::AppletResourceUserId) ->  bool IsEnabled
         public long IsUnintendedHomeButtonInputProtectionEnabled(ServiceCtx context)
         {
@@ -869,6 +813,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(132)]
         // EnableUnintendedHomeButtonInputProtection(bool Enable, uint Unknown0, nn::applet::AppletResourceUserId)
         public long EnableUnintendedHomeButtonInputProtection(ServiceCtx context)
         {
@@ -881,6 +826,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(133)] // 5.0.0+
         // SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1
         public long SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
         {
@@ -905,6 +851,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(200)]
         // GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo
         public long GetVibrationDeviceInfo(ServiceCtx context)
         {
@@ -924,6 +871,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(201)]
         // SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId)
         public long SendVibrationValue(ServiceCtx context)
         {
@@ -951,6 +899,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(202)]
         // GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue
         public long GetActualVibrationValue(ServiceCtx context)
         {
@@ -974,6 +923,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(203)]
         // CreateActiveVibrationDeviceList() -> object<nn::hid::IActiveVibrationDeviceList>
         public long CreateActiveVibrationDeviceList(ServiceCtx context)
         {
@@ -982,6 +932,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(204)]
         // PermitVibration(bool Enable)
         public long PermitVibration(ServiceCtx context)
         {
@@ -992,6 +943,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(205)]
         // IsVibrationPermitted() -> bool IsEnabled
         public long IsVibrationPermitted(ServiceCtx context)
         {
@@ -1002,6 +954,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(206)]
         // SendVibrationValues(nn::applet::AppletResourceUserId, buffer<array<nn::hid::VibrationDeviceHandle>, type: 9>, buffer<array<nn::hid::VibrationValue>, type: 9>)
         public long SendVibrationValues(ServiceCtx context)
         {
@@ -1026,6 +979,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(207)] // 4.0.0+
         // SendVibrationGcErmCommand(nn::hid::VibrationDeviceHandle, nn::hid::VibrationGcErmCommand, nn::applet::AppletResourceUserId)
         public long SendVibrationGcErmCommand(ServiceCtx context)
         {
@@ -1038,6 +992,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(208)] // 4.0.0+
         // GetActualVibrationGcErmCommand(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationGcErmCommand
         public long GetActualVibrationGcErmCommand(ServiceCtx context)
         {
@@ -1051,6 +1006,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(209)] // 4.0.0+
         // BeginPermitVibrationSession(nn::applet::AppletResourceUserId)
         public long BeginPermitVibrationSession(ServiceCtx context)
         {
@@ -1061,6 +1017,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(210)] // 4.0.0+
         // EndPermitVibrationSession()
         public long EndPermitVibrationSession(ServiceCtx context)
         {
@@ -1069,6 +1026,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(300)]
         // ActivateConsoleSixAxisSensor(nn::applet::AppletResourceUserId)
         public long ActivateConsoleSixAxisSensor(ServiceCtx context)
         {
@@ -1079,6 +1037,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(301)]
         // StartConsoleSixAxisSensor(nn::hid::ConsoleSixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long StartConsoleSixAxisSensor(ServiceCtx context)
         {
@@ -1090,6 +1049,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(302)]
         // StopConsoleSixAxisSensor(nn::hid::ConsoleSixAxisSensorHandle, nn::applet::AppletResourceUserId)
         public long StopConsoleSixAxisSensor(ServiceCtx context)
         {
@@ -1101,6 +1061,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(303)] // 5.0.0+
         // ActivateSevenSixAxisSensor(nn::applet::AppletResourceUserId)
         public long ActivateSevenSixAxisSensor(ServiceCtx context)
         {
@@ -1111,6 +1072,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(304)] // 5.0.0+
         // StartSevenSixAxisSensor(nn::applet::AppletResourceUserId)
         public long StartSevenSixAxisSensor(ServiceCtx context)
         {
@@ -1121,6 +1083,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(305)] // 5.0.0+
         // StopSevenSixAxisSensor(nn::applet::AppletResourceUserId)
         public long StopSevenSixAxisSensor(ServiceCtx context)
         {
@@ -1131,6 +1094,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(306)] // 5.0.0+
         // InitializeSevenSixAxisSensor(array<nn::sf::NativeHandle>, ulong Counter0, array<nn::sf::NativeHandle>, ulong Counter1, nn::applet::AppletResourceUserId)
         public long InitializeSevenSixAxisSensor(ServiceCtx context)
         {
@@ -1145,6 +1109,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(307)] // 5.0.0+
         // FinalizeSevenSixAxisSensor(nn::applet::AppletResourceUserId)
         public long FinalizeSevenSixAxisSensor(ServiceCtx context)
         {
@@ -1155,6 +1120,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(308)] // 5.0.0+
         // SetSevenSixAxisSensorFusionStrength(float Strength, nn::applet::AppletResourceUserId)
         public long SetSevenSixAxisSensorFusionStrength(ServiceCtx context)
         {
@@ -1166,6 +1132,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(309)] // 5.0.0+
         // GetSevenSixAxisSensorFusionStrength(nn::applet::AppletResourceUserId) -> float Strength
         public long GetSevenSixAxisSensorFusionStrength(ServiceCtx context)
         {
@@ -1178,6 +1145,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(400)]
         // IsUsbFullKeyControllerEnabled() -> bool IsEnabled
         public long IsUsbFullKeyControllerEnabled(ServiceCtx context)
         {
@@ -1188,6 +1156,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(401)]
         // EnableUsbFullKeyController(bool Enable)
         public long EnableUsbFullKeyController(ServiceCtx context)
         {
@@ -1198,6 +1167,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(402)]
         // IsUsbFullKeyControllerConnected(uint Unknown0) -> bool Connected
         public long IsUsbFullKeyControllerConnected(ServiceCtx context)
         {
@@ -1210,6 +1180,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(403)] // 4.0.0+
         // HasBattery(uint NpadId) -> bool HasBattery
         public long HasBattery(ServiceCtx context)
         {
@@ -1222,6 +1193,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(404)] // 4.0.0+
         // HasLeftRightBattery(uint NpadId) -> bool HasLeftBattery, bool HasRightBattery
         public long HasLeftRightBattery(ServiceCtx context)
         {
@@ -1235,6 +1207,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(405)] // 4.0.0+
         // GetNpadInterfaceType(uint NpadId) -> uchar InterfaceType
         public long GetNpadInterfaceType(ServiceCtx context)
         {
@@ -1247,6 +1220,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(406)] // 4.0.0+
         // GetNpadLeftRightInterfaceType(uint NpadId) -> uchar LeftInterfaceType, uchar RightInterfaceType
         public long GetNpadLeftRightInterfaceType(ServiceCtx context)
         {
@@ -1260,6 +1234,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(500)] // 5.0.0+
         // GetPalmaConnectionHandle(uint Unknown0, nn::applet::AppletResourceUserId) -> nn::hid::PalmaConnectionHandle
         public long GetPalmaConnectionHandle(ServiceCtx context)
         {
@@ -1275,6 +1250,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(501)] // 5.0.0+
         // InitializePalma(nn::hid::PalmaConnectionHandle)
         public long InitializePalma(ServiceCtx context)
         {
@@ -1287,6 +1263,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(502)] // 5.0.0+
         // AcquirePalmaOperationCompleteEvent(nn::hid::PalmaConnectionHandle) -> nn::sf::NativeHandle
         public long AcquirePalmaOperationCompleteEvent(ServiceCtx context)
         {
@@ -1304,6 +1281,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(503)] // 5.0.0+
         // GetPalmaOperationInfo(nn::hid::PalmaConnectionHandle) -> long Unknown0, buffer<Unknown>
         public long GetPalmaOperationInfo(ServiceCtx context)
         {
@@ -1318,6 +1296,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(504)] // 5.0.0+
         // PlayPalmaActivity(nn::hid::PalmaConnectionHandle, ulong Unknown0)
         public long PlayPalmaActivity(ServiceCtx context)
         {
@@ -1331,6 +1310,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(505)] // 5.0.0+
         // SetPalmaFrModeType(nn::hid::PalmaConnectionHandle, ulong FrModeType)
         public long SetPalmaFrModeType(ServiceCtx context)
         {
@@ -1344,6 +1324,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(506)] // 5.0.0+
         // ReadPalmaStep(nn::hid::PalmaConnectionHandle)
         public long ReadPalmaStep(ServiceCtx context)
         {
@@ -1354,6 +1335,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(507)] // 5.0.0+
         // EnablePalmaStep(nn::hid::PalmaConnectionHandle, bool Enable)
         public long EnablePalmaStep(ServiceCtx context)
         {
@@ -1367,18 +1349,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
-        // SuspendPalmaStep(nn::hid::PalmaConnectionHandle)
-        public long SuspendPalmaStep(ServiceCtx context)
-        {
-            int palmaConnectionHandle = context.RequestData.ReadInt32();
-
-            Logger.PrintStub(LogClass.ServiceHid, new { palmaConnectionHandle });
-
-            _palmaOperationCompleteEvent.ReadableEvent.Signal();
-
-            return 0;
-        }
-
+        [Command(508)] // 5.0.0+
         // ResetPalmaStep(nn::hid::PalmaConnectionHandle)
         public long ResetPalmaStep(ServiceCtx context)
         {
@@ -1391,6 +1362,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(509)] // 5.0.0+
         // ReadPalmaApplicationSection(nn::hid::PalmaConnectionHandle, ulong Unknown0, ulong Unknown1)
         public long ReadPalmaApplicationSection(ServiceCtx context)
         {
@@ -1403,6 +1375,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(510)] // 5.0.0+
         // WritePalmaApplicationSection(nn::hid::PalmaConnectionHandle, ulong Unknown0, ulong Unknown1, nn::hid::PalmaApplicationSectionAccessBuffer)
         public long WritePalmaApplicationSection(ServiceCtx context)
         {
@@ -1418,6 +1391,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(511)] // 5.0.0+
         // ReadPalmaUniqueCode(nn::hid::PalmaConnectionHandle)
         public long ReadPalmaUniqueCode(ServiceCtx context)
         {
@@ -1428,6 +1402,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(512)] // 5.0.0+
         // SetPalmaUniqueCodeInvalid(nn::hid::PalmaConnectionHandle)
         public long SetPalmaUniqueCodeInvalid(ServiceCtx context)
         {
@@ -1438,6 +1413,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(1000)]
         // SetNpadCommunicationMode(long CommunicationMode, nn::applet::AppletResourceUserId)
         public long SetNpadCommunicationMode(ServiceCtx context)
         {
@@ -1449,6 +1425,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             return 0;
         }
 
+        [Command(1001)]
         // GetNpadCommunicationMode() -> long CommunicationMode
         public long GetNpadCommunicationMode(ServiceCtx context)
         {

+ 6 - 29
Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs

@@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.Input;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Hid.Irs
 {
@@ -12,35 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
     {
         private int _irsensorSharedMemoryHandle = 0;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IIrSensorServer(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 302, ActivateIrsensor                  },
-                { 303, DeactivateIrsensor                },
-                { 304, GetIrsensorSharedMemoryHandle     },
-              //{ 305, StopImageProcessor                },
-              //{ 306, RunMomentProcessor                },
-              //{ 307, RunClusteringProcessor            },
-              //{ 308, RunImageTransferProcessor         },
-              //{ 309, GetImageTransferProcessorState    },
-              //{ 310, RunTeraPluginProcessor            },
-                { 311, GetNpadIrCameraHandle             },
-              //{ 312, RunPointingProcessor              },
-              //{ 313, SuspendImageProcessor             },
-              //{ 314, CheckFirmwareVersion              }, // 3.0.0+
-              //{ 315, SetFunctionLevel                  }, // 4.0.0+
-              //{ 316, RunImageTransferExProcessor       }, // 4.0.0+
-              //{ 317, RunIrLedProcessor                 }, // 4.0.0+
-              //{ 318, StopImageProcessorAsync           }, // 4.0.0+
-                { 319, ActivateIrsensorWithFunctionLevel }, // 4.0.0+
-            };
-        }
+        public IIrSensorServer(ServiceCtx context) { }
 
+        [Command(302)]
         // ActivateIrsensor(nn::applet::AppletResourceUserId, pid)
         public long ActivateIrsensor(ServiceCtx context)
         {
@@ -51,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
             return 0;
         }
 
+        [Command(303)]
         // DeactivateIrsensor(nn::applet::AppletResourceUserId, pid)
         public long DeactivateIrsensor(ServiceCtx context)
         {
@@ -61,6 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
             return 0;
         }
 
+        [Command(304)]
         // GetIrsensorSharedMemoryHandle(nn::applet::AppletResourceUserId, pid) -> handle<copy>
         public long GetIrsensorSharedMemoryHandle(ServiceCtx context)
         {
@@ -77,6 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
             return 0;
         }
 
+        [Command(311)]
         // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle
         public long GetNpadIrCameraHandle(ServiceCtx context)
         {
@@ -99,6 +75,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
             return 0;
         }
 
+        [Command(319)] // 4.0.0+
         // ActivateIrsensorWithFunctionLevel(nn::applet::AppletResourceUserId, nn::irsensor::PackedFunctionLevel, pid)
         public long ActivateIrsensorWithFunctionLevel(ServiceCtx context)
         {

+ 2 - 2
Ryujinx.HLE/HOS/Services/IIpcService.cs

@@ -1,10 +1,10 @@
-using Ryujinx.HLE.HOS.Ipc;
 using System.Collections.Generic;
+using System.Reflection;
 
 namespace Ryujinx.HLE.HOS.Services
 {
     interface IIpcService
     {
-        IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
+        IReadOnlyDictionary<int, MethodInfo> Commands { get; }
     }
 }

+ 19 - 6
Ryujinx.HLE/HOS/Services/IpcService.cs

@@ -7,12 +7,14 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using Ryujinx.Profiler;
+using System.Reflection;
+using System.Linq;
 
 namespace Ryujinx.HLE.HOS.Services
 {
     abstract class IpcService : IIpcService
     {
-        public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
+        public IReadOnlyDictionary<int, MethodInfo> Commands { get; }
 
         private IdDictionary _domainObjects;
 
@@ -22,6 +24,13 @@ namespace Ryujinx.HLE.HOS.Services
 
         public IpcService()
         {
+            Commands = Assembly.GetExecutingAssembly().GetTypes()
+                .Where(type => type == GetType())
+                .SelectMany(type => type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
+                .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandAttribute))
+                .Select(command => (((CommandAttribute)command).Id, methodInfo)))
+                .ToDictionary(command => command.Id, command => command.methodInfo);
+
             _domainObjects = new IdDictionary();
 
             _selfId = -1;
@@ -90,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services
             long sfciMagic =      context.RequestData.ReadInt64();
             int  commandId = (int)context.RequestData.ReadInt64();
 
-            bool serviceExists = service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest);
+            bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
 
             if (ServiceConfiguration.IgnoreMissingServices || serviceExists)
             {
@@ -100,19 +109,23 @@ namespace Ryujinx.HLE.HOS.Services
 
                 if (serviceExists)
                 {
-                    Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}");
+                    Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}");
 
                     ProfileConfig profile = Profiles.ServiceCall;
-                    profile.SessionGroup  = service.GetType().Name;
-                    profile.SessionItem   = processRequest.Method.Name;
+
+                    profile.SessionGroup = service.GetType().Name;
+                    profile.SessionItem  = processRequest.Name;
 
                     Profile.Begin(profile);
-                    result = processRequest(context);
+
+                    result = (long)processRequest.Invoke(service, new object[] { context });
+
                     Profile.End(profile);
                 }
                 else
                 {
                     string serviceName;
+
                     DummyService dummyService = service as DummyService;
 
                     serviceName = (dummyService == null) ? service.GetType().FullName : dummyService.ServiceName;

+ 6 - 14
Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs

@@ -98,10 +98,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
     [Service("ldr:ro")]
     class IRoInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private const int MaxNrr = 0x40;
         private const int MaxNro = 0x40;
 
@@ -115,15 +111,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
 
         public IRoInterface(ServiceCtx context)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, LoadNro    },
-                { 1, UnloadNro  },
-                { 2, LoadNrr    },
-                { 3, UnloadNrr  },
-                { 4, Initialize }
-            };
-
             _nrrInfos = new List<NrrInfo>(MaxNrr);
             _nroInfos = new List<NroInfo>(MaxNro);
         }
@@ -448,6 +435,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return MakeError(ErrorModule.Loader, LoaderErr.BadNroAddress);
         }
 
+        [Command(0)]
         // LoadNro(u64, u64, u64, u64, u64, pid) -> u64
         public long LoadNro(ServiceCtx context)
         {
@@ -485,6 +473,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return result;
         }
 
+        [Command(1)]
         // UnloadNro(u64, u64, pid)
         public long UnloadNro(ServiceCtx context)
         {
@@ -508,6 +497,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return result;
         }
 
+        [Command(2)]
         // LoadNrr(u64, u64, u64, pid)
         public long LoadNrr(ServiceCtx context)
         {
@@ -540,6 +530,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return result;
         }
 
+        [Command(3)]
         // UnloadNrr(u64, u64, pid)
         public long UnloadNrr(ServiceCtx context)
         {
@@ -563,6 +554,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return result;
         }
 
+        [Command(4)]
         // Initialize(u64, pid, KObject)
         public long Initialize(ServiceCtx context)
         {
@@ -572,4 +564,4 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
             return 0;
         }
     }
-}
+}

+ 3 - 14
Ryujinx.HLE/HOS/Services/Lm/ILogService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Lm
 {
     [Service("lm")]
     class ILogService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ILogService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Initialize }
-            };
-        }
+        public ILogService(ServiceCtx context) { }
 
+        [Command(0)]
+        // Initialize(u64, pid) -> object<nn::lm::ILogger>
         public long Initialize(ServiceCtx context)
         {
             MakeObject(context, new ILogger());

+ 4 - 15
Ryujinx.HLE/HOS/Services/Lm/ILogger.cs

@@ -1,6 +1,4 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
@@ -8,21 +6,12 @@ namespace Ryujinx.HLE.HOS.Services.Lm
 {
     class ILogger : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ILogger()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Log }
-            };
-        }
+        public ILogger() { }
 
+        [Command(0)]
+        // Log(buffer<unknown, 0x21>)
         public long Log(ServiceCtx context)
         {
-
             (long bufPos, long bufSize) = context.Request.GetBufferType0x21();
             byte[] logBuffer = context.Memory.ReadBytes(bufPos, bufSize);
 
@@ -94,4 +83,4 @@ namespace Ryujinx.HLE.HOS.Services.Lm
             return 0;
         }
     }
-}
+}

+ 105 - 115
Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs

@@ -1,8 +1,6 @@
 using LibHac.Fs.NcaUtils;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 using System.Text;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
@@ -12,95 +10,89 @@ namespace Ryujinx.HLE.HOS.Services.Lr
 {
     class ILocationResolver : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private StorageId _storageId;
 
         public ILocationResolver(StorageId storageId)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  ResolveProgramPath                      },
-                { 1,  RedirectProgramPath                     },
-                { 2,  ResolveApplicationControlPath           },
-                { 3,  ResolveApplicationHtmlDocumentPath      },
-                { 4,  ResolveDataPath                         },
-                { 5,  RedirectApplicationControlPath          },
-                { 6,  RedirectApplicationHtmlDocumentPath     },
-                { 7,  ResolveApplicationLegalInformationPath  },
-                { 8,  RedirectApplicationLegalInformationPath },
-                { 9,  Refresh                                 },
-                { 10, SetProgramNcaPath2                      },
-                { 11, ClearLocationResolver2                  },
-                { 12, DeleteProgramNcaPath                    },
-                { 13, DeleteControlNcaPath                    },
-                { 14, DeleteDocHtmlNcaPath                    },
-                { 15, DeleteInfoHtmlNcaPath                   }
-            };
-
             _storageId = storageId;
         }
 
-        // DeleteInfoHtmlNcaPath()
-        public long DeleteInfoHtmlNcaPath(ServiceCtx context)
+        [Command(0)]
+        // ResolveProgramPath()
+        public long ResolveProgramPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Manual);
-
-            return 0;
+            if (ResolvePath(context, titleId, ContentType.Program))
+            {
+                return 0;
+            }
+            else
+            {
+                return MakeError(ErrorModule.Lr, LrErr.ProgramLocationEntryNotFound);
+            }
         }
 
-        // DeleteDocHtmlNcaPath()
-        public long DeleteDocHtmlNcaPath(ServiceCtx context)
+        [Command(1)]
+        // RedirectProgramPath()
+        public long RedirectProgramPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Manual);
+            RedirectPath(context, titleId, 0, ContentType.Program);
 
             return 0;
         }
 
-        // DeleteControlNcaPath()
-        public long DeleteControlNcaPath(ServiceCtx context)
+        [Command(2)]
+        // ResolveApplicationControlPath()
+        public long ResolveApplicationControlPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Control);
-
-            return 0;
+            if (ResolvePath(context, titleId, ContentType.Control))
+            {
+                return 0;
+            }
+            else
+            {
+                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
+            }
         }
 
-        // DeleteProgramNcaPath()
-        public long DeleteProgramNcaPath(ServiceCtx context)
+        [Command(3)]
+        // ResolveApplicationHtmlDocumentPath()
+        public long ResolveApplicationHtmlDocumentPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Program);
-
-            return 0;
-        }
-
-        // ClearLocationResolver2()
-        public long ClearLocationResolver2(ServiceCtx context)
-        {
-            context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
-
-            return 0;
+            if (ResolvePath(context, titleId, ContentType.Manual))
+            {
+                return 0;
+            }
+            else
+            {
+                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
+            }
         }
 
-        // SetProgramNcaPath2()
-        public long SetProgramNcaPath2(ServiceCtx context)
+        [Command(4)]
+        // ResolveDataPath()
+        public long ResolveDataPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 1, ContentType.Program);
-
-            return 0;
+            if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData))
+            {
+                return 0;
+            }
+            else
+            {
+                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
+            }
         }
 
+        [Command(5)]
         // RedirectApplicationControlPath()
         public long RedirectApplicationControlPath(ServiceCtx context)
         {
@@ -111,6 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.Lr
             return 0;
         }
 
+        [Command(6)]
         // RedirectApplicationHtmlDocumentPath()
         public long RedirectApplicationHtmlDocumentPath(ServiceCtx context)
         {
@@ -121,6 +114,23 @@ namespace Ryujinx.HLE.HOS.Services.Lr
             return 0;
         }
 
+        [Command(7)]
+        // ResolveApplicationLegalInformationPath()
+        public long ResolveApplicationLegalInformationPath(ServiceCtx context)
+        {
+            long titleId = context.RequestData.ReadInt64();
+
+            if (ResolvePath(context, titleId, ContentType.Manual))
+            {
+                return 0;
+            }
+            else
+            {
+                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
+            }
+        }
+
+        [Command(8)]
         // RedirectApplicationLegalInformationPath()
         public long RedirectApplicationLegalInformationPath(ServiceCtx context)
         {
@@ -131,97 +141,77 @@ namespace Ryujinx.HLE.HOS.Services.Lr
             return 0;
         }
 
-        // ResolveDataPath()
-        public long ResolveDataPath(ServiceCtx context)
+        [Command(9)]
+        // Refresh()
+        public long Refresh(ServiceCtx context)
         {
-            long titleId = context.RequestData.ReadInt64();
+            context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
 
-            if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData))
-            {
-                return 0;
-            }
-            else
-            {
-                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
-            }
+            return 0;
         }
 
-        // ResolveApplicationHtmlDocumentPath()
-        public long ResolveApplicationHtmlDocumentPath(ServiceCtx context)
+        [Command(10)]
+        // SetProgramNcaPath2()
+        public long SetProgramNcaPath2(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Manual))
-            {
-                return 0;
-            }
-            else
-            {
-                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
-            }
+            RedirectPath(context, titleId, 1, ContentType.Program);
+
+            return 0;
         }
 
-        // ResolveApplicationLegalInformationPath()
-        public long ResolveApplicationLegalInformationPath(ServiceCtx context)
+        [Command(11)]
+        // ClearLocationResolver2()
+        public long ClearLocationResolver2(ServiceCtx context)
         {
-            long titleId = context.RequestData.ReadInt64();
+            context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
 
-            if (ResolvePath(context, titleId, ContentType.Manual))
-            {
-                return 0;
-            }
-            else
-            {
-                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
-            }
+            return 0;
         }
 
-        // ResolveApplicationControlPath()
-        public long ResolveApplicationControlPath(ServiceCtx context)
+        [Command(12)]
+        // DeleteProgramNcaPath()
+        public long DeleteProgramNcaPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Control))
-            {
-                return 0;
-            }
-            else
-            {
-                return MakeError(ErrorModule.Lr, LrErr.AccessDenied);
-            }
+            DeleteContentPath(context, titleId, ContentType.Program);
+
+            return 0;
         }
 
-        // RedirectProgramPath()
-        public long RedirectProgramPath(ServiceCtx context)
+        [Command(13)]
+        // DeleteControlNcaPath()
+        public long DeleteControlNcaPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 0, ContentType.Program);
+            DeleteContentPath(context, titleId, ContentType.Control);
 
             return 0;
         }
 
-        // Refresh()
-        public long Refresh(ServiceCtx context)
+        [Command(14)]
+        // DeleteDocHtmlNcaPath()
+        public long DeleteDocHtmlNcaPath(ServiceCtx context)
         {
-            context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
+            long titleId = context.RequestData.ReadInt64();
+
+            DeleteContentPath(context, titleId, ContentType.Manual);
 
             return 0;
         }
 
-        // ResolveProgramPath()
-        public long ResolveProgramPath(ServiceCtx context)
+        [Command(15)]
+        // DeleteInfoHtmlNcaPath()
+        public long DeleteInfoHtmlNcaPath(ServiceCtx context)
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Program))
-            {
-                return 0;
-            }
-            else
-            {
-                return MakeError(ErrorModule.Lr, LrErr.ProgramLocationEntryNotFound);
-            }
+            DeleteContentPath(context, titleId, ContentType.Manual);
+
+            return 0;
         }
 
         private void RedirectPath(ServiceCtx context, long titleId, int flag, ContentType contentType)

+ 4 - 15
Ryujinx.HLE/HOS/Services/Lr/ILocationResolverManager.cs

@@ -1,24 +1,13 @@
-using System.Collections.Generic;
-using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.FileSystem;
 
 namespace Ryujinx.HLE.HOS.Services.Lr
 {
     [Service("lr")]
     class ILocationResolverManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ILocationResolverManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, OpenLocationResolver }
-            };
-        }
+        public ILocationResolverManager(ServiceCtx context) { }
 
+        [Command(0)]
         // OpenLocationResolver()
         private long OpenLocationResolver(ServiceCtx context)
         {
@@ -29,4 +18,4 @@ namespace Ryujinx.HLE.HOS.Services.Lr
             return 0;
         }
     }
-}
+}

+ 9 - 20
Ryujinx.HLE/HOS/Services/Mm/IRequest.cs

@@ -1,31 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Mm
 {
     [Service("mm:u")]
     class IRequest : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IRequest(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>()
-            {
-                { 0, InitializeOld },
-                { 1, FinalizeOld   },
-                { 2, SetAndWaitOld },
-                { 3, GetOld        },
-                { 4, Initialize    },
-                { 5, Finalize      },
-                { 6, SetAndWait    },
-                { 7, Get           }
-            };
-        }
+        public IRequest(ServiceCtx context) { }
 
+        [Command(0)]
         // InitializeOld(u32, u32, u32)
         public long InitializeOld(ServiceCtx context)
         {
@@ -38,6 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(1)]
         // FinalizeOld(u32)
         public long FinalizeOld(ServiceCtx context)
         {
@@ -48,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(2)]
         // SetAndWaitOld(u32, u32, u32)
         public long SetAndWaitOld(ServiceCtx context)
         {
@@ -59,6 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(3)]
         // GetOld(u32) -> u32
         public long GetOld(ServiceCtx context)
         {
@@ -71,6 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(4)]
         // Initialize()
         public long Initialize(ServiceCtx context)
         {
@@ -79,6 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(5)]
         // Finalize(u32)
         public long Finalize(ServiceCtx context)
         {
@@ -89,6 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(6)]
         // SetAndWait(u32, u32, u32)
         public long SetAndWait(ServiceCtx context)
         {
@@ -101,6 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm
             return 0;
         }
 
+        [Command(7)]
         // Get(u32) -> u32
         public long Get(ServiceCtx context)
         {

+ 2 - 15
Ryujinx.HLE/HOS/Services/Ncm/IContentManager.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Ncm
+namespace Ryujinx.HLE.HOS.Services.Ncm
 {
     [Service("ncm")]
     class IContentManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IContentManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                //...
-            };
-        }
+        public IContentManager(ServiceCtx context) { }
     }
 }

+ 3 - 16
Ryujinx.HLE/HOS/Services/Ncm/IContentStorage.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Ncm
+namespace Ryujinx.HLE.HOS.Services.Ncm
 {
     class IContentStorage : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IContentStorage()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-
-            };
-        }
+        public IContentStorage() { }
     }
-}
+}

+ 27 - 37
Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs

@@ -1,5 +1,4 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE.Exceptions;
+using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
@@ -18,42 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
 
         private List<Device> _devices = new List<Device>();
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IUser()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  Initialize                    },
-                { 1,  Finalize                      },
-                { 2,  ListDevices                   },
-                { 3,  StartDetection                },
-                { 4,  StopDetection                 },
-                { 5,  Mount                         },
-                { 6,  Unmount                       },
-                { 7,  OpenApplicationArea           },
-                { 8,  GetApplicationArea            },
-                { 9,  SetApplicationArea            },
-                { 10, Flush                         },
-                { 11, Restore                       },
-                { 12, CreateApplicationArea         },
-                { 13, GetTagInfo                    },
-                { 14, GetRegisterInfo               },
-                { 15, GetCommonInfo                 },
-                { 16, GetModelInfo                  },
-                { 17, AttachActivateEvent           },
-                { 18, AttachDeactivateEvent         },
-                { 19, GetState                      },
-                { 20, GetDeviceState                },
-                { 21, GetNpadId                     },
-                { 22, GetApplicationAreaSize        },
-                { 23, AttachAvailabilityChangeEvent }, // 3.0.0+
-                { 24, RecreateApplicationArea       }, // 3.0.0+
-            };
-        }
+        public IUser() { }
 
+        [Command(0)]
         // Initialize(u64, u64, pid, buffer<unknown, 5>)
         public long Initialize(ServiceCtx context)
         {
@@ -87,6 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return 0;
         }
 
+        [Command(1)]
         // Finalize()
         public long Finalize(ServiceCtx context)
         {
@@ -101,6 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return 0;
         }
 
+        [Command(2)]
         // ListDevices() -> (u32, buffer<unknown, 0xa>)
         public long ListDevices(ServiceCtx context)
         {
@@ -127,90 +95,105 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return 0;
         }
 
+        [Command(3)]
         // StartDetection(bytes<8, 4>)
         public long StartDetection(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(4)]
         // StopDetection(bytes<8, 4>)
         public long StopDetection(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(5)]
         // Mount(bytes<8, 4>, u32, u32)
         public long Mount(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(6)]
         // Unmount(bytes<8, 4>)
         public long Unmount(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(7)]
         // OpenApplicationArea(bytes<8, 4>, u32)
         public long OpenApplicationArea(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(8)]
         // GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
         public long GetApplicationArea(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(9)]
         // SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
         public long SetApplicationArea(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(10)]
         // Flush(bytes<8, 4>)
         public long Flush(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(11)]
         // Restore(bytes<8, 4>)
         public long Restore(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(12)]
         // CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
         public long CreateApplicationArea(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(13)]
         // GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
         public long GetTagInfo(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(14)]
         // GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
         public long GetRegisterInfo(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(15)]
         // GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
         public long GetCommonInfo(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(16)]
         // GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
         public long GetModelInfo(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(17)]
         // AttachActivateEvent(bytes<8, 4>) -> handle<copy>
         public long AttachActivateEvent(ServiceCtx context)
         {
@@ -239,6 +222,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
         }
 
+        [Command(18)]
         // AttachDeactivateEvent(bytes<8, 4>) -> handle<copy>
         public long AttachDeactivateEvent(ServiceCtx context)
         {
@@ -267,6 +251,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
         }
 
+        [Command(19)]
         // GetState() -> u32
         public long GetState(ServiceCtx context)
         {
@@ -275,6 +260,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return 0;
         }
 
+        [Command(20)]
         // GetDeviceState(bytes<8, 4>) -> u32
         public long GetDeviceState(ServiceCtx context)
         {
@@ -295,6 +281,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
         }
 
+        [Command(21)]
         // GetNpadId(bytes<8, 4>) -> u32
         public long GetNpadId(ServiceCtx context)
         {
@@ -313,12 +300,14 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
         }
 
+        [Command(22)]
         // GetApplicationAreaSize(bytes<8, 4>) -> u32
         public long GetApplicationAreaSize(ServiceCtx context)
         {
             throw new ServiceNotImplementedException(context);
         }
 
+        [Command(23)] // 3.0.0+
         // AttachAvailabilityChangeEvent() -> handle<copy>
         public long AttachAvailabilityChangeEvent(ServiceCtx context)
         {
@@ -337,6 +326,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
             return 0;
         }
 
+        [Command(24)] // 3.0.0+
         // RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
         public long RecreateApplicationArea(ServiceCtx context)
         {

+ 4 - 15
Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUserManager.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
 {
     [Service("nfp:user")]
     class IUserManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IUserManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetUserInterface }
-            };
-        }
+        public IUserManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // CreateUserInterface() -> object<nn::nfp::detail::IUser>
         public long GetUserInterface(ServiceCtx context)
         {
             MakeObject(context, new IUser());

+ 6 - 15
Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs

@@ -1,7 +1,5 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Net.NetworkInformation;
@@ -13,19 +11,10 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
 {
     class IGeneralService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IGeneralService()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 4, CreateRequest        },
-                { 12, GetCurrentIpAddress }
-            };
-        }
+        public IGeneralService() { }
 
+        [Command(4)]
+        // CreateRequest(u32) -> object<nn::nifm::detail::IRequest>
         public long CreateRequest(ServiceCtx context)
         {
             int unknown = context.RequestData.ReadInt32();
@@ -37,6 +26,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(12)]
+        // GetCurrentIpAddress() -> nn::nifm::IpV4Address
         public long GetCurrentIpAddress(ServiceCtx context)
         {
             if (!NetworkInterface.GetIsNetworkAvailable())
@@ -55,4 +46,4 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
     }
-}
+}

+ 12 - 15
Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs

@@ -3,35 +3,22 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Nifm
 {
     class IRequest : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _event0;
         private KEvent _event1;
 
         public IRequest(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  GetRequestState                 },
-                { 1,  GetResult                       },
-                { 2,  GetSystemEventReadableHandles   },
-                { 3,  Cancel                          },
-                { 4,  Submit                          },
-                { 11, SetConnectionConfirmationOption }
-            };
-
             _event0 = new KEvent(system);
             _event1 = new KEvent(system);
         }
 
+        [Command(0)]
+        // GetRequestState() -> u32
         public long GetRequestState(ServiceCtx context)
         {
             context.ResponseData.Write(1);
@@ -41,6 +28,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(1)]
+        // GetResult()
         public long GetResult(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNifm);
@@ -48,6 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(2)]
+        // GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
         public long GetSystemEventReadableHandles(ServiceCtx context)
         {
             if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success)
@@ -65,6 +56,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(3)]
+        // Cancel()
         public long Cancel(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNifm);
@@ -72,6 +65,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(4)]
+        // Submit()
         public long Submit(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNifm);
@@ -79,6 +74,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(11)]
+        // SetConnectionConfirmationOption(i8)
         public long SetConnectionConfirmationOption(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNifm);

+ 5 - 15
Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs

@@ -1,24 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Nifm
 {
     [Service("nifm:u")]
     class IStaticService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IStaticService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 4, CreateGeneralServiceOld },
-                { 5, CreateGeneralService    }
-            };
-        }
+        public IStaticService(ServiceCtx context) { }
 
+        [Command(4)]
+        // CreateGeneralServiceOld() -> object<nn::nifm::detail::IGeneralService>
         public long CreateGeneralServiceOld(ServiceCtx context)
         {
             MakeObject(context, new IGeneralService());
@@ -26,6 +14,8 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
             return 0;
         }
 
+        [Command(5)] // 3.0.0+
+        // CreateGeneralService(u64, pid) -> object<nn::nifm::detail::IGeneralService>
         public long CreateGeneralService(ServiceCtx context)
         {
             MakeObject(context, new IGeneralService());

+ 5 - 14
Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs

@@ -1,25 +1,14 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Ns
 {
     [Service("aoc:u")]
     class IAddOnContentManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IAddOnContentManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 2, CountAddOnContent },
-                { 3, ListAddOnContent  }
-            };
-        }
+        public IAddOnContentManager(ServiceCtx context) { }
 
+        [Command(2)]
+        // CountAddOnContent(u64, pid) -> u32
         public static long CountAddOnContent(ServiceCtx context)
         {
             context.ResponseData.Write(0);
@@ -29,6 +18,8 @@ namespace Ryujinx.HLE.HOS.Services.Ns
             return 0;
         }
 
+        [Command(3)]
+        // ListAddOnContent(u32, u32, u64, pid) -> (u32, buffer<u32, 6>)
         public static long ListAddOnContent(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNs);

+ 4 - 14
Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs

@@ -1,7 +1,5 @@
 using LibHac;
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 namespace Ryujinx.HLE.HOS.Services.Ns
@@ -9,18 +7,10 @@ namespace Ryujinx.HLE.HOS.Services.Ns
     [Service("ns:am")]
     class IApplicationManagerInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationManagerInterface(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 400, GetApplicationControlData }
-            };
-        }
+        public IApplicationManagerInterface(ServiceCtx context) { }
 
+        [Command(400)]
+        // GetApplicationControlData(unknown<0x10>) -> (unknown<4>, buffer<unknown, 6>)
         public long GetApplicationControlData(ServiceCtx context)
         {
             long position = context.Request.ReceiveBuff[0].Position;
@@ -220,4 +210,4 @@ namespace Ryujinx.HLE.HOS.Services.Ns
             return 0;
         }
     }
-}
+}

+ 3 - 14
Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs

@@ -1,24 +1,13 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Ns
 {
     [Service("ns:am2")]
     [Service("ns:ec")]
     class IServiceGetterInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IServiceGetterInterface(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 7996, GetApplicationManagerInterface }
-            };
-        }
+        public IServiceGetterInterface(ServiceCtx context) { }
 
+        [Command(7996)]
+        // GetApplicationManagerInterface() -> object<nn::ns::detail::IApplicationManagerInterface>
         public long GetApplicationManagerInterface(ServiceCtx context)
         {
             MakeObject(context, new IApplicationManagerInterface(context));

+ 1 - 14
Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Ns
 {
     [Service("ns:su")]
     class ISystemUpdateInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISystemUpdateInterface(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public ISystemUpdateInterface(ServiceCtx context) { }
     }
 }

+ 1 - 14
Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs

@@ -1,21 +1,8 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Ns
 {
     [Service("ns:vm")]
     class IVulnerabilityManagerInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IVulnerabilityManagerInterface(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public IVulnerabilityManagerInterface(ServiceCtx context) { }
     }
 }

+ 19 - 18
Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs

@@ -20,10 +20,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv
     {
         private delegate int IoctlProcessor(ServiceCtx context, int cmd);
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private static Dictionary<string, IoctlProcessor> _ioctlProcessors =
                    new Dictionary<string, IoctlProcessor>()
         {
@@ -42,19 +38,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv
 
         public INvDrvServices(ServiceCtx context)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>()
-            {
-                { 0,  Open                   },
-                { 1,  Ioctl                  },
-                { 2,  Close                  },
-                { 3,  Initialize             },
-                { 4,  QueryEvent             },
-                { 8,  SetClientPid           },
-                { 9,  DumpGraphicsMemoryInfo },
-                { 11, Ioctl                  },
-                { 13, FinishInitialize       }
-            };
-
             _event = new KEvent(context.Device.System);
         }
 
@@ -63,6 +46,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             Fds = new GlobalStateTable();
         }
 
+        [Command(0)]
+        // Open(buffer<bytes, 5> path) -> (u32 fd, u32 error_code)
         public long Open(ServiceCtx context)
         {
             long namePtr = context.Request.SendBuff[0].Position;
@@ -77,6 +62,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(1)]
+        // Ioctl(u32 fd, u32 rq_id, buffer<bytes, 0x21>) -> (u32 error_code, buffer<bytes, 0x22>)
+        [Command(11)] // 3.0.0+
+        // Ioctl2(u32, u32, buffer<bytes, 0x21>, buffer<bytes, 0x21>) -> (u32, buffer<bytes, 0x22>)
         public long Ioctl(ServiceCtx context)
         {
             int fd  = context.RequestData.ReadInt32();
@@ -101,6 +90,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(2)]
+        // Close(u32 fd) -> u32 error_code
         public long Close(ServiceCtx context)
         {
             int fd = context.RequestData.ReadInt32();
@@ -112,6 +103,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(3)]
+        // Initialize(u32 transfer_memory_size, handle<copy, process> current_process, handle<copy, transfer_memory> transfer_memory) -> u32 error_code
         public long Initialize(ServiceCtx context)
         {
             long transferMemSize   = context.RequestData.ReadInt64();
@@ -124,6 +117,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(4)]
+        // QueryEvent(u32 fd, u32 event_id) -> (u32, handle<copy, event>)
         public long QueryEvent(ServiceCtx context)
         {
             int fd      = context.RequestData.ReadInt32();
@@ -142,6 +137,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(8)]
+        // SetClientPID(u64, pid) -> u32 error_code
         public long SetClientPid(ServiceCtx context)
         {
             long pid = context.RequestData.ReadInt64();
@@ -151,6 +148,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(9)]
+        // DumpGraphicsMemoryInfo()
         public long DumpGraphicsMemoryInfo(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNv);
@@ -158,6 +157,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             return 0;
         }
 
+        [Command(13)]
+        // FinishInitialize(unknown<8>)
         public long FinishInitialize(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceNv);
@@ -232,4 +233,4 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             NvMapIoctl.UnloadProcess(process);
         }
     }
-}
+}

+ 4 - 12
Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs

@@ -1,30 +1,20 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Pctl
 {
     class IParentalControlService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private bool _initialized = false;
 
         private bool _needInitialize;
 
         public IParentalControlService(bool needInitialize = true)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 1,    Initialize                       },
-                { 1001, CheckFreeCommunicationPermission }
-            };
-
             _needInitialize = needInitialize;
         }
 
+        [Command(1)] // 4.0.0+
+        // Initialize()
         public long Initialize(ServiceCtx context)
         {
             if (_needInitialize && !_initialized)
@@ -39,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Services.Pctl
             return 0;
         }
 
+        [Command(1001)]
+        // CheckFreeCommunicationPermission()
         public long CheckFreeCommunicationPermission(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServicePctl);

+ 5 - 15
Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs

@@ -1,6 +1,3 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Pctl
 {
     [Service("pctl")]
@@ -9,19 +6,10 @@ namespace Ryujinx.HLE.HOS.Services.Pctl
     [Service("pctl:s")]
     class IParentalControlServiceFactory : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IParentalControlServiceFactory(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, CreateService                  },
-                { 1, CreateServiceWithoutInitialize }
-            };
-        }
+        public IParentalControlServiceFactory(ServiceCtx context) { }
 
+        [Command(0)]
+        // CreateService(u64, pid) -> object<nn::pctl::detail::ipc::IParentalControlService>
         public long CreateService(ServiceCtx context)
         {
             MakeObject(context, new IParentalControlService());
@@ -29,6 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Pctl
             return 0;
         }
 
+        [Command(1)] // 4.0.0+
+        // CreateServiceWithoutInitialize(u64, pid) -> object<nn::pctl::detail::ipc::IParentalControlService>
         public long CreateServiceWithoutInitialize(ServiceCtx context)
         {
             MakeObject(context, new IParentalControlService(false));

+ 13 - 17
Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs

@@ -2,30 +2,16 @@ using Ryujinx.HLE.HOS.Font;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Pl
 {
     [Service("pl:u")]
     class ISharedFontManager : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISharedFontManager(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, RequestLoad                    },
-                { 1, GetLoadState                   },
-                { 2, GetFontSize                    },
-                { 3, GetSharedMemoryAddressOffset   },
-                { 4, GetSharedMemoryNativeHandle    },
-                { 5, GetSharedFontInOrderOfPriority }
-            };
-        }
+        public ISharedFontManager(ServiceCtx context) { }
 
+        [Command(0)]
+        // RequestLoad(u32)
         public long RequestLoad(ServiceCtx context)
         {
             SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
@@ -35,6 +21,8 @@ namespace Ryujinx.HLE.HOS.Services.Pl
             return 0;
         }
 
+        [Command(1)]
+        // GetLoadState(u32) -> u32
         public long GetLoadState(ServiceCtx context)
         {
             SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
@@ -46,6 +34,8 @@ namespace Ryujinx.HLE.HOS.Services.Pl
             return 0;
         }
 
+        [Command(2)]
+        // GetFontSize(u32) -> u32
         public long GetFontSize(ServiceCtx context)
         {
             SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
@@ -55,6 +45,8 @@ namespace Ryujinx.HLE.HOS.Services.Pl
             return 0;
         }
 
+        [Command(3)]
+        // GetSharedMemoryAddressOffset(u32) -> u32
         public long GetSharedMemoryAddressOffset(ServiceCtx context)
         {
             SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
@@ -64,6 +56,8 @@ namespace Ryujinx.HLE.HOS.Services.Pl
             return 0;
         }
 
+        [Command(4)]
+        // GetSharedMemoryNativeHandle() -> handle<copy>
         public long GetSharedMemoryNativeHandle(ServiceCtx context)
         {
             context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
@@ -78,6 +72,8 @@ namespace Ryujinx.HLE.HOS.Services.Pl
             return 0;
         }
 
+        [Command(5)]
+        // GetSharedFontInOrderOfPriority(bytes<8, 1>) -> (u8, u32, buffer<unknown, 6>, buffer<unknown, 6>, buffer<unknown, 6>)
         public long GetSharedFontInOrderOfPriority(ServiceCtx context)
         {
             long languageCode = context.RequestData.ReadInt64();

+ 3 - 15
Ryujinx.HLE/HOS/Services/Pm/IShellInterface.cs

@@ -1,23 +1,11 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Pm
+namespace Ryujinx.HLE.HOS.Services.Pm
 {
     [Service("pm:shell")]
     class IShellInterface : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IShellInterface(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 6, GetApplicationPid }
-            };
-        }
+        public IShellInterface(ServiceCtx context) { }
 
+        [Command(6)]
         // GetApplicationPid() -> u64
         public long GetApplicationPid(ServiceCtx context)
         {

+ 3 - 13
Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs

@@ -1,6 +1,4 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Prepo
 {
@@ -8,18 +6,10 @@ namespace Ryujinx.HLE.HOS.Services.Prepo
     [Service("prepo:u")]
     class IPrepoService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IPrepoService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 10101, SaveReportWithUser }
-            };
-        }
+        public IPrepoService(ServiceCtx context) { }
 
+        [Command(10101)]
+        // SaveReportWithUser(nn::account::Uid, u64, pid, buffer<u8, 9>, buffer<bytes, 5>)
         public static long SaveReportWithUser(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServicePrepo);

+ 4 - 15
Ryujinx.HLE/HOS/Services/Psm/IPsmServer.cs

@@ -1,6 +1,4 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Psm
 {
@@ -14,20 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             UsbC
         }
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IPsmServer(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetBatteryChargePercentage },
-                { 1, GetChargerType             },
-                { 7, OpenSession                }
-            };
-        }
+        public IPsmServer(ServiceCtx context) { }
 
+        [Command(0)]
         // GetBatteryChargePercentage() -> u32
         public static long GetBatteryChargePercentage(ServiceCtx context)
         {
@@ -40,6 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(1)]
         // GetChargerType() -> u32
         public static long GetChargerType(ServiceCtx context)
         {
@@ -52,6 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(7)]
         // OpenSession() -> IPsmSession
         public long OpenSession(ServiceCtx context)
         {

+ 5 - 14
Ryujinx.HLE/HOS/Services/Psm/IPsmSession.cs

@@ -2,34 +2,21 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Psm
 {
     class IPsmSession : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _stateChangeEvent;
         private int    _stateChangeEventHandle;
 
         public IPsmSession(Horizon system)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, BindStateChangeEvent                     },
-                { 1, UnbindStateChangeEvent                   },
-                { 2, SetChargerTypeChangeEventEnabled         },
-                { 3, SetPowerSupplyChangeEventEnabled         },
-                { 4, SetBatteryVoltageStateChangeEventEnabled }
-            };
-
             _stateChangeEvent       = new KEvent(system);
             _stateChangeEventHandle = -1;
         }
 
+        [Command(0)]
         // BindStateChangeEvent() -> KObject
         public long BindStateChangeEvent(ServiceCtx context)
         {
@@ -50,6 +37,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(1)]
         // UnbindStateChangeEvent()
         public long UnbindStateChangeEvent(ServiceCtx context)
         {
@@ -64,6 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(2)]
         // SetChargerTypeChangeEventEnabled(u8)
         public long SetChargerTypeChangeEventEnabled(ServiceCtx context)
         {
@@ -74,6 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(3)]
         // SetPowerSupplyChangeEventEnabled(u8)
         public long SetPowerSupplyChangeEventEnabled(ServiceCtx context)
         {
@@ -84,6 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Psm
             return 0;
         }
 
+        [Command(4)]
         // SetBatteryVoltageStateChangeEventEnabled(u8)
         public long SetBatteryVoltageStateChangeEventEnabled(ServiceCtx context)
         {

+ 9 - 23
Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs

@@ -1,8 +1,6 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.SystemState;
 using System;
-using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -11,27 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Set
     [Service("set")]
     class ISettingsServer : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISettingsServer(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetLanguageCode                },
-                { 1, GetAvailableLanguageCodes      },
-                { 2, MakeLanguageCode               }, // 4.0.0+
-                { 3, GetAvailableLanguageCodeCount  },
-              //{ 4, GetRegionCode                  },
-                { 5, GetAvailableLanguageCodes2     },
-                { 6, GetAvailableLanguageCodeCount2 },
-              //{ 7, GetKeyCodeMap                  }, // 4.0.0+
-                { 8, GetQuestFlag                   }, // 5.0.0+
-              //{ 9, GetKeyCodeMap2                 }, // 6.0.0+
-            };
-        }
+        public ISettingsServer(ServiceCtx context) { }
 
+        [Command(0)]
         // GetLanguageCode() -> nn::settings::LanguageCode
         public static long GetLanguageCode(ServiceCtx context)
         {
@@ -40,6 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(1)]
         // GetAvailableLanguageCodes() -> (u32, buffer<nn::settings::LanguageCode, 0xa>)
         public static long GetAvailableLanguageCodes(ServiceCtx context)
         {
@@ -50,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
                     0xF);
         }
 
+        [Command(2)] // 4.0.0+
         // MakeLanguageCode(nn::settings::Language language_index) -> nn::settings::LanguageCode
         public static long MakeLanguageCode(ServiceCtx context)
         {
@@ -65,6 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(3)]
         // GetAvailableLanguageCodeCount() -> u32
         public static long GetAvailableLanguageCodeCount(ServiceCtx context)
         {
@@ -73,6 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(5)]
         // GetAvailableLanguageCodes2() -> (u32, buffer<nn::settings::LanguageCode, 6>)
         public static long GetAvailableLanguageCodes2(ServiceCtx context)
         {
@@ -83,6 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
                     SystemStateMgr.LanguageCodes.Length);
         }
 
+        [Command(6)]
         // GetAvailableLanguageCodeCount2() -> u32
         public static long GetAvailableLanguageCodeCount2(ServiceCtx context)
         {
@@ -91,6 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(8)] // 5.0.0+
         // GetQuestFlag() -> bool
         public static long GetQuestFlag(ServiceCtx context)
         {
@@ -122,4 +108,4 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
     }
-}
+}

+ 7 - 18
Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs

@@ -2,10 +2,8 @@ using LibHac.Fs;
 using LibHac.Fs.NcaUtils;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.SystemState;
 using System;
-using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
@@ -14,28 +12,16 @@ namespace Ryujinx.HLE.HOS.Services.Set
     [Service("set:sys")]
     class ISystemSettingsServer : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISystemSettingsServer(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 3,  GetFirmwareVersion  },
-                { 4,  GetFirmwareVersion2  },
-                { 23, GetColorSetId        },
-                { 24, SetColorSetId        },
-                { 38, GetSettingsItemValue }
-            };
-        }
+        public ISystemSettingsServer(ServiceCtx context) { }
 
+        [Command(3)]
         // GetFirmwareVersion() -> buffer<nn::settings::system::FirmwareVersion, 0x1a, 0x100>
         public static long GetFirmwareVersion(ServiceCtx context)
         {
             return GetFirmwareVersion2(context);
         }
 
+        [Command(4)]
         // GetFirmwareVersion2() -> buffer<nn::settings::system::FirmwareVersion, 0x1a, 0x100>
         public static long GetFirmwareVersion2(ServiceCtx context)
         {
@@ -95,6 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(23)]
         // GetColorSetId() -> i32
         public static long GetColorSetId(ServiceCtx context)
         {
@@ -103,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(24)]
         // GetColorSetId() -> i32
         public static long SetColorSetId(ServiceCtx context)
         {
@@ -113,6 +101,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
             return 0;
         }
 
+        [Command(38)]
         // GetSettingsItemValue(buffer<nn::settings::SettingsName, 0x19, 0x48>, buffer<nn::settings::SettingsItemKey, 0x19, 0x48>) -> (u64, buffer<unknown, 6, 0>)
         public static long GetSettingsItemValue(ServiceCtx context)
         {
@@ -206,4 +195,4 @@ namespace Ryujinx.HLE.HOS.Services.Set
             }
         }
     }
-}
+}

+ 11 - 21
Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs

@@ -1,5 +1,4 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using System;
 using System.Collections.Generic;
 using System.Net;
@@ -13,25 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
     [Service("sfdnsres")]
     class IResolver : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IResolver(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,  SetDnsAddressesPrivate },
-                { 1,  GetDnsAddressesPrivate },
-                { 2,  GetHostByName          },
-                { 3,  GetHostByAddress       },
-                { 4,  GetHostStringError     },
-                { 5,  GetGaiStringError      },
-                { 8,  RequestCancelHandle    },
-                { 9,  CancelSocketCall       },
-                { 11, ClearDnsAddresses      }
-            };
-        }
+        public IResolver(ServiceCtx context) { }
 
         private long SerializeHostEnt(ServiceCtx context, IPHostEntry hostEntry, List<IPAddress> addresses = null)
         {
@@ -159,6 +140,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return result;
         }
 
+        [Command(0)]
         // SetDnsAddressesPrivate(u32, buffer<unknown, 5, 0>)
         public long SetDnsAddressesPrivate(ServiceCtx context)
         {
@@ -172,6 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return MakeError(ErrorModule.Os, 1023);
         }
 
+        [Command(1)]
         // GetDnsAddressPrivate(u32) -> buffer<unknown, 6, 0>
         public long GetDnsAddressesPrivate(ServiceCtx context)
         {
@@ -183,6 +166,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return MakeError(ErrorModule.Os, 1023);
         }
 
+        [Command(2)]
         // GetHostByName(u8, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
         public long GetHostByName(ServiceCtx context)
         {
@@ -262,6 +246,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return 0;
         }
 
+        [Command(3)]
         // GetHostByAddr(u32, u32, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
         public long GetHostByAddress(ServiceCtx context)
         {
@@ -331,6 +316,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return 0;
         }
 
+        [Command(4)]
         // GetHostStringError(u32) -> buffer<unknown, 6, 0>
         public long GetHostStringError(ServiceCtx context)
         {
@@ -347,6 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return resultCode;
         }
 
+        [Command(5)]
         // GetGaiStringError(u32) -> buffer<unknown, 6, 0>
         public long GetGaiStringError(ServiceCtx context)
         {
@@ -363,6 +350,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return resultCode;
         }
 
+        [Command(8)]
         // RequestCancelHandle(u64, pid) -> u32
         public long RequestCancelHandle(ServiceCtx context)
         {
@@ -375,6 +363,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return 0;
         }
 
+        [Command(9)]
         // CancelSocketCall(u32, u64, pid)
         public long CancelSocketCall(ServiceCtx context)
         {
@@ -386,6 +375,7 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return 0;
         }
 
+        [Command(11)]
         // ClearDnsAddresses(u32)
         public long ClearDnsAddresses(ServiceCtx context)
         {
@@ -396,4 +386,4 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
             return 0;
         }
     }
-}
+}

+ 8 - 12
Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs

@@ -16,24 +16,12 @@ namespace Ryujinx.HLE.HOS.Services.Sm
     {
         private Dictionary<string, Type> _services;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private ConcurrentDictionary<string, KPort> _registeredServices;
 
         private bool _isInitialized;
 
         public IUserInterface(ServiceCtx context = null)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, Initialize        },
-                { 1, GetService        },
-                { 2, RegisterService   },
-                { 3, UnregisterService }
-            };
-
             _registeredServices = new ConcurrentDictionary<string, KPort>();
 
             _services = Assembly.GetExecutingAssembly().GetTypes()
@@ -51,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm
             port.ClientPort.Service = new IUserInterface();
         }
 
+        [Command(0)]
+        // Initialize(pid, u64 reserved)
         public long Initialize(ServiceCtx context)
         {
             _isInitialized = true;
@@ -58,6 +48,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm
             return 0;
         }
 
+        [Command(1)]
+        // GetService(ServiceName name) -> handle<move, session>
         public long GetService(ServiceCtx context)
         {
             if (!_isInitialized)
@@ -117,6 +109,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm
             return 0;
         }
 
+        [Command(2)]
+        // RegisterService(ServiceName name, u8, u32 maxHandles) -> handle<move, port>
         public long RegisterService(ServiceCtx context)
         {
             if (!_isInitialized)
@@ -158,6 +152,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm
             return 0;
         }
 
+        [Command(3)]
+        // UnregisterService(ServiceName name)
         public long UnregisterService(ServiceCtx context)
         {
             if (!_isInitialized)

+ 3 - 12
Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs

@@ -1,6 +1,4 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System;
-using System.Collections.Generic;
+using System;
 using System.Security.Cryptography;
 
 namespace Ryujinx.HLE.HOS.Services.Spl
@@ -8,22 +6,15 @@ namespace Ryujinx.HLE.HOS.Services.Spl
     [Service("csrng")]
     class IRandomInterface : IpcService, IDisposable
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private RNGCryptoServiceProvider _rng;
 
         public IRandomInterface(ServiceCtx context)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetRandomBytes }
-            };
-
             _rng = new RNGCryptoServiceProvider();
         }
 
+        [Command(0)]
+        // GetRandomBytes() -> buffer<unknown, 6>
         public long GetRandomBytes(ServiceCtx context)
         {
             byte[] randomBytes = new byte[context.Request.ReceiveBuff[0].Size];

+ 1 - 14
Ryujinx.HLE/HOS/Services/Ssl/ISslContext.cs

@@ -1,20 +1,7 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Ssl
 {
     class ISslContext : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISslContext()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                // ...
-            };
-        }
+        public ISslContext() { }
     }
 }

+ 3 - 14
Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs

@@ -1,25 +1,13 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Ssl
 {
     [Service("ssl")]
     class ISslService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISslService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, CreateContext       },
-                { 5, SetInterfaceVersion }
-            };
-        }
+        public ISslService(ServiceCtx context) { }
 
+        [Command(0)]
         // CreateContext(nn::ssl::sf::SslVersion, u64, pid) -> object<nn::ssl::sf::ISslContext>
         public long CreateContext(ServiceCtx context)
         {
@@ -33,6 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
             return 0;
         }
 
+        [Command(5)]
         // SetInterfaceVersion(u32)
         public long SetInterfaceVersion(ServiceCtx context)
         {

+ 8 - 31
Ryujinx.HLE/HOS/Services/Time/IStaticService.cs

@@ -1,7 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Time
 {
@@ -12,39 +11,11 @@ namespace Ryujinx.HLE.HOS.Services.Time
     {
         private int _timeSharedMemoryNativeHandle = 0;
 
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private static readonly DateTime StartupDate = DateTime.UtcNow;
 
-        public IStaticService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,   GetStandardUserSystemClock                               },
-                { 1,   GetStandardNetworkSystemClock                            },
-                { 2,   GetStandardSteadyClock                                   },
-                { 3,   GetTimeZoneService                                       },
-                { 4,   GetStandardLocalSystemClock                              },
-              //{ 5,   GetEphemeralNetworkSystemClock                           }, // 4.0.0+
-                { 20,  GetSharedMemoryNativeHandle                              }, // 6.0.0+
-              //{ 30,  GetStandardNetworkClockOperationEventReadableHandle      }, // 6.0.0+
-              //{ 31,  GetEphemeralNetworkClockOperationEventReadableHandle     }, // 6.0.0+
-              //{ 50,  SetStandardSteadyClockInternalOffset                     }, // 4.0.0+
-              //{ 100, IsStandardUserSystemClockAutomaticCorrectionEnabled      },
-              //{ 101, SetStandardUserSystemClockAutomaticCorrectionEnabled     },
-              //{ 102, GetStandardUserSystemClockInitialYear                    }, // 5.0.0+
-              //{ 200, IsStandardNetworkSystemClockAccuracySufficient           }, // 3.0.0+
-              //{ 201, GetStandardUserSystemClockAutomaticCorrectionUpdatedTime }, // 6.0.0+
-                { 300, CalculateMonotonicSystemClockBaseTimePoint               }, // 4.0.0+
-              //{ 400, GetClockSnapshot                                         }, // 4.0.0+
-              //{ 401, GetClockSnapshotFromSystemClockContext                   }, // 4.0.0+
-              //{ 500, CalculateStandardUserSystemClockDifferenceByUser         }, // 4.0.0+
-              //{ 501, CalculateSpanBetween                                     }, // 4.0.0+
-            };
-        }
+        public IStaticService(ServiceCtx context) { }
 
+        [Command(0)]
         // GetStandardUserSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
         public long GetStandardUserSystemClock(ServiceCtx context)
         {
@@ -53,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(1)]
         // GetStandardNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
         public long GetStandardNetworkSystemClock(ServiceCtx context)
         {
@@ -61,6 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(2)]
         // GetStandardSteadyClock() -> object<nn::timesrv::detail::service::ISteadyClock>
         public long GetStandardSteadyClock(ServiceCtx context)
         {
@@ -69,6 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(3)]
         // GetTimeZoneService() -> object<nn::timesrv::detail::service::ITimeZoneService>
         public long GetTimeZoneService(ServiceCtx context)
         {
@@ -77,6 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(4)]
         // GetStandardLocalSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
         public long GetStandardLocalSystemClock(ServiceCtx context)
         {
@@ -85,6 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(20)] // 6.0.0+
         // GetSharedMemoryNativeHandle() -> handle<copy>
         public long GetSharedMemoryNativeHandle(ServiceCtx context)
         {
@@ -101,6 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(300)] // 4.0.0+
         // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> u64
         public long CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context)
         {

+ 6 - 13
Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs

@@ -1,29 +1,18 @@
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Time
 {
     class ISteadyClock : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private ulong _testOffset;
 
         public ISteadyClock()
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetCurrentTimePoint },
-                { 1, GetTestOffset       },
-                { 2, SetTestOffset       }
-            };
-
             _testOffset = 0;
         }
 
+        [Command(0)]
+        // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
         public long GetCurrentTimePoint(ServiceCtx context)
         {
             context.ResponseData.Write((long)(System.Diagnostics.Process.GetCurrentProcess().StartTime - DateTime.Now).TotalSeconds);
@@ -36,6 +25,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(1)]
+        // GetTestOffset() -> nn::TimeSpanType
         public long GetTestOffset(ServiceCtx context)
         {
             context.ResponseData.Write(_testOffset);
@@ -43,6 +34,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(2)]
+        // SetTestOffset(nn::TimeSpanType)
         public long SetTestOffset(ServiceCtx context)
         {
             _testOffset = context.RequestData.ReadUInt64();

+ 13 - 23
Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs

@@ -1,38 +1,20 @@
-using Ryujinx.HLE.HOS.Ipc;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Time
 {
     class ISystemClock : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 
         private SystemClockType _clockType;
-
-        private DateTime _systemClockContextEpoch;
-
-        private long _systemClockTimePoint;
-
-        private byte[] _systemClockContextEnding;
-
-        private long _timeOffset;
+        private DateTime        _systemClockContextEpoch;
+        private long            _systemClockTimePoint;
+        private byte[]          _systemClockContextEnding;
+        private long            _timeOffset;
 
         public ISystemClock(SystemClockType clockType)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetCurrentTime        },
-                { 1, SetCurrentTime        },
-                { 2, GetSystemClockContext },
-                { 3, SetSystemClockContext }
-            };
-
-            _clockType           = clockType;
+            _clockType                = clockType;
             _systemClockContextEpoch  = System.Diagnostics.Process.GetCurrentProcess().StartTime;
             _systemClockContextEnding = new byte[0x10];
             _timeOffset               = 0;
@@ -46,6 +28,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             _systemClockTimePoint = (long)(_systemClockContextEpoch - Epoch).TotalSeconds;
         }
 
+        [Command(0)]
+        // GetCurrentTime() -> nn::time::PosixTime
         public long GetCurrentTime(ServiceCtx context)
         {
             DateTime currentTime = DateTime.Now;
@@ -61,6 +45,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(1)]
+        // SetCurrentTime(nn::time::PosixTime)
         public long SetCurrentTime(ServiceCtx context)
         {
             DateTime currentTime = DateTime.Now;
@@ -76,6 +62,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(2)]
+        // GetSystemClockContext() -> nn::time::SystemClockContext
         public long GetSystemClockContext(ServiceCtx context)
         {
             context.ResponseData.Write((long)(_systemClockContextEpoch - Epoch).TotalSeconds);
@@ -92,6 +80,8 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(3)]
+        // SetSystemClockContext(nn::time::SystemClockContext)
         public long SetSystemClockContext(ServiceCtx context)
         {
             long newSystemClockEpoch     = context.RequestData.ReadInt64();

+ 11 - 24
Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs

@@ -1,10 +1,8 @@
 using ChocolArm64.Memory;
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Services.Time.TimeZone;
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
@@ -13,28 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
 {
     class ITimeZoneService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ITimeZoneService()
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0,   GetDeviceLocationName               },
-                { 1,   SetDeviceLocationName               },
-                { 2,   GetTotalLocationNameCount           },
-                { 3,   LoadLocationNameList                },
-                { 4,   LoadTimeZoneRule                    },
-              //{ 5,   GetTimeZoneRuleVersion              }, // 2.0.0+
-              //{ 6,   GetDeviceLocationNameAndUpdatedTime }, // 5.0.0+
-                { 100, ToCalendarTime                      },
-                { 101, ToCalendarTimeWithMyRule            },
-                { 201, ToPosixTime                         },
-                { 202, ToPosixTimeWithMyRule               }
-            };
-        }
+        public ITimeZoneService() { }
 
+        [Command(0)]
         // GetDeviceLocationName() -> nn::time::LocationName
         public long GetDeviceLocationName(ServiceCtx context)
         {
@@ -57,6 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(1)]
         // SetDeviceLocationName(nn::time::LocationName)
         public long SetDeviceLocationName(ServiceCtx context)
         {
@@ -65,6 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return TimeZoneManager.Instance.SetDeviceLocationName(locationName);
         }
 
+        [Command(2)]
         // GetTotalLocationNameCount() -> u32
         public long GetTotalLocationNameCount(ServiceCtx context)
         {
@@ -73,6 +54,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return 0;
         }
 
+        [Command(3)]
         // LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
         public long LoadLocationNameList(ServiceCtx context)
         {
@@ -108,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return errorCode;
         }
 
+        [Command(4)]
         // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer<nn::time::TimeZoneRule, 0x16>
         public long LoadTimeZoneRule(ServiceCtx context)
         {
@@ -136,6 +119,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return resultCode;
         }
 
+        [Command(100)]
         // ToCalendarTime(nn::time::PosixTime time, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
         public long ToCalendarTime(ServiceCtx context)
         {
@@ -163,6 +147,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return resultCode;
         }
 
+        [Command(101)]
         // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
         public long ToCalendarTimeWithMyRule(ServiceCtx context)
         {
@@ -178,6 +163,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return resultCode;
         }
 
+        [Command(201)]
         // ToPosixTime(nn::time::CalendarTime calendarTime, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
         public long ToPosixTime(ServiceCtx context)
         {
@@ -210,6 +196,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return resultCode;
         }
 
+        [Command(202)]
         // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
         public long ToPosixTimeWithMyRule(ServiceCtx context)
         {
@@ -231,4 +218,4 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return resultCode;
         }
     }
-}
+}

+ 32 - 26
Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs

@@ -1,7 +1,6 @@
 using ChocolArm64.Memory;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
-using System.Collections.Generic;
 using System;
 using System.IO;
 using System.Text;
@@ -13,45 +12,26 @@ namespace Ryujinx.HLE.HOS.Services.Vi
 {
     class IApplicationDisplayService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private IdDictionary _displays;
 
         public IApplicationDisplayService()
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 100,  GetRelayService                      },
-                { 101,  GetSystemDisplayService              },
-                { 102,  GetManagerDisplayService             },
-                { 103,  GetIndirectDisplayTransactionService },
-                { 1000, ListDisplays                         },
-                { 1010, OpenDisplay                          },
-                { 1020, CloseDisplay                         },
-                { 1102, GetDisplayResolution                 },
-                { 2020, OpenLayer                            },
-                { 2021, CloseLayer                           },
-                { 2030, CreateStrayLayer                     },
-                { 2031, DestroyStrayLayer                    },
-                { 2101, SetLayerScalingMode                  },
-                { 2102, ConvertScalingMode                   },
-                { 5202, GetDisplayVSyncEvent                 }
-            };
-
             _displays = new IdDictionary();
         }
 
+        [Command(100)]
+        // GetRelayService() -> object<nns::hosbinder::IHOSBinderDriver>
         public long GetRelayService(ServiceCtx context)
         {
-            MakeObject(context, new IhosBinderDriver(
+            MakeObject(context, new IHOSBinderDriver(
                 context.Device.System,
                 context.Device.Gpu.Renderer));
 
             return 0;
         }
 
+        [Command(101)]
+        // GetSystemDisplayService() -> object<nn::visrv::sf::ISystemDisplayService>
         public long GetSystemDisplayService(ServiceCtx context)
         {
             MakeObject(context, new ISystemDisplayService(this));
@@ -59,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(102)]
+        // GetManagerDisplayService() -> object<nn::visrv::sf::IManagerDisplayService>
         public long GetManagerDisplayService(ServiceCtx context)
         {
             MakeObject(context, new IManagerDisplayService(this));
@@ -66,15 +48,19 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(103)] // 2.0.0+
+        // GetIndirectDisplayTransactionService() -> object<nns::hosbinder::IHOSBinderDriver>
         public long GetIndirectDisplayTransactionService(ServiceCtx context)
         {
-            MakeObject(context, new IhosBinderDriver(
+            MakeObject(context, new IHOSBinderDriver(
                 context.Device.System,
                 context.Device.Gpu.Renderer));
 
             return 0;
         }
 
+        [Command(1000)]
+        // ListDisplays() -> (u64, buffer<nn::vi::DisplayInfo, 6>)
         public long ListDisplays(ServiceCtx context)
         {
             long recBuffPtr = context.Request.ReceiveBuff[0].Position;
@@ -93,6 +79,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(1010)]
+        // OpenDisplay(nn::vi::DisplayName) -> u64
         public long OpenDisplay(ServiceCtx context)
         {
             string name = GetDisplayName(context);
@@ -104,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(1020)]
+        // CloseDisplay(u64)
         public long CloseDisplay(ServiceCtx context)
         {
             int displayId = context.RequestData.ReadInt32();
@@ -113,6 +103,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(1102)]
+        // GetDisplayResolution(u64) -> (u64, u64)
         public long GetDisplayResolution(ServiceCtx context)
         {
             long displayId = context.RequestData.ReadInt32();
@@ -123,6 +115,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2020)]
+        // OpenLayer(nn::vi::DisplayName, u64, nn::applet::AppletResourceUserId, pid) -> (u64, buffer<bytes, 6>)
         public long OpenLayer(ServiceCtx context)
         {
             long layerId = context.RequestData.ReadInt64();
@@ -139,6 +133,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2021)]
+        // CloseLayer(u64)
         public long CloseLayer(ServiceCtx context)
         {
             long layerId = context.RequestData.ReadInt64();
@@ -146,6 +142,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2030)]
+        // CreateStrayLayer(u32, u64) -> (u64, u64, buffer<bytes, 6>)
         public long CreateStrayLayer(ServiceCtx context)
         {
             long layerFlags = context.RequestData.ReadInt64();
@@ -165,11 +163,15 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2031)]
+        // DestroyStrayLayer(u64)
         public long DestroyStrayLayer(ServiceCtx context)
         {
             return 0;
         }
 
+        [Command(2101)]
+        // SetLayerScalingMode(u32, u64)
         public long SetLayerScalingMode(ServiceCtx context)
         {
             int  scalingMode = context.RequestData.ReadInt32();
@@ -178,6 +180,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2102)] // 5.0.0+
+        // ConvertScalingMode(unknown) -> unknown
         public long ConvertScalingMode(ServiceCtx context)
         {
             SrcScalingMode scalingMode = (SrcScalingMode)context.RequestData.ReadInt32();
@@ -216,6 +220,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return null;
         }
 
+        [Command(5202)]
+        // GetDisplayVsyncEvent(u64) -> handle<copy>
         public long GetDisplayVSyncEvent(ServiceCtx context)
         {
             string name = GetDisplayName(context);

+ 3 - 14
Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
     [Service("vi:u")]
     class IApplicationRootService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IApplicationRootService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, GetDisplayService }
-            };
-        }
+        public IApplicationRootService(ServiceCtx context) { }
 
+        [Command(0)]
+        // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
         public long GetDisplayService(ServiceCtx context)
         {
             int serviceType = context.RequestData.ReadInt32();

+ 24 - 29
Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs

@@ -4,30 +4,17 @@ using Ryujinx.HLE.HOS.Kernel.Common;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Android;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
-    class IhosBinderDriver : IpcService, IDisposable
+    class IHOSBinderDriver : IpcService, IDisposable
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
         private KEvent _binderEvent;
 
         private NvFlinger _flinger;
 
-        public IhosBinderDriver(Horizon system, IGalRenderer renderer)
+        public IHOSBinderDriver(Horizon system, IGalRenderer renderer)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 0, TransactParcel     },
-                { 1, AdjustRefcount     },
-                { 2, GetNativeHandle    },
-                { 3, TransactParcelAuto }
-            };
-
             _binderEvent = new KEvent(system);
 
             _binderEvent.ReadableEvent.Signal();
@@ -35,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             _flinger = new NvFlinger(renderer, _binderEvent);
         }
 
+        [Command(0)]
+        // TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>
         public long TransactParcel(ServiceCtx context)
         {
             int id   = context.RequestData.ReadInt32();
@@ -50,20 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return _flinger.ProcessParcelRequest(context, data, code);
         }
 
-        public long 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 _flinger.ProcessParcelRequest(context, data, code);
-        }
-
+        [Command(1)]
+        // AdjustRefcount(s32, s32, s32)
         public long AdjustRefcount(ServiceCtx context)
         {
             int id     = context.RequestData.ReadInt32();
@@ -73,6 +50,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2)]
+        // GetNativeHandle(s32, s32) -> handle<copy>
         public long GetNativeHandle(ServiceCtx context)
         {
             int  id  = context.RequestData.ReadInt32();
@@ -88,6 +67,22 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(3)] // 3.0.0+
+        // TransactParcelAuto(s32, u32, u32, buffer<unknown, 21, 0>) -> buffer<unknown, 22, 0>
+        public long 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 _flinger.ProcessParcelRequest(context, data, code);
+        }
+
         public void Dispose()
         {
             Dispose(true);

+ 19 - 13
Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs

@@ -1,27 +1,18 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
     class IManagerDisplayService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
+        private static IApplicationDisplayService _applicationDisplayService;
 
         public IManagerDisplayService(IApplicationDisplayService applicationDisplayService)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 2010, CreateManagedLayer                         },
-                { 2011, DestroyManagedLayer                        },
-                { 2012, applicationDisplayService.CreateStrayLayer },
-                { 6000, AddToLayerStack                            },
-                { 6002, SetLayerVisibility                         }
-            };
+            _applicationDisplayService = applicationDisplayService;
         }
 
+        [Command(2010)]
+        // CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64
         public static long CreateManagedLayer(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);
@@ -31,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2011)]
+        // DestroyManagedLayer(u64)
         public long DestroyManagedLayer(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);
@@ -38,6 +31,17 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2012)] // 7.0.0+
+        // CreateStrayLayer(u32, u64) -> (u64, u64, buffer<bytes, 6>)
+        public static long CreateStrayLayer(ServiceCtx context)
+        {
+            Logger.PrintStub(LogClass.ServiceVi);
+
+            return _applicationDisplayService.CreateStrayLayer(context);
+        }
+
+        [Command(6000)]
+        // AddToLayerStack(u32, u64)
         public static long AddToLayerStack(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);
@@ -45,6 +49,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(6002)]
+        // SetLayerVisibility(b8, u64)
         public static long SetLayerVisibility(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);

+ 3 - 14
Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
     [Service("vi:m")]
     class IManagerRootService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public IManagerRootService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 2, GetDisplayService }
-            };
-        }
+        public IManagerRootService(ServiceCtx context) { }
 
+        [Command(2)]
+        // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
         public long GetDisplayService(ServiceCtx context)
         {
             int serviceType = context.RequestData.ReadInt32();

+ 17 - 12
Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs

@@ -1,26 +1,18 @@
 using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
     class ISystemDisplayService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
+        private static IApplicationDisplayService _applicationDisplayService;
 
         public ISystemDisplayService(IApplicationDisplayService applicationDisplayService)
         {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 2205, SetLayerZ                                  },
-                { 2207, SetLayerVisibility                         },
-                { 2312, applicationDisplayService.CreateStrayLayer },
-                { 3200, GetDisplayMode                             }
-            };
+            _applicationDisplayService = applicationDisplayService;
         }
 
+        [Command(2205)]
+        // SetLayerZ(u64, u64)
         public static long SetLayerZ(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);
@@ -28,6 +20,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2207)]
+        // SetLayerVisibility(b8, u64)
         public static long SetLayerVisibility(ServiceCtx context)
         {
             Logger.PrintStub(LogClass.ServiceVi);
@@ -35,6 +29,17 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             return 0;
         }
 
+        [Command(2312)] // 1.0.0-6.2.0
+        // CreateStrayLayer(u32, u64) -> (u64, u64, buffer<bytes, 6>)
+        public static long CreateStrayLayer(ServiceCtx context)
+        {
+            Logger.PrintStub(LogClass.ServiceVi);
+
+            return _applicationDisplayService.CreateStrayLayer(context);
+        }
+
+        [Command(3200)]
+        // GetDisplayMode(u64) -> nn::vi::DisplayModeInfo
         public static long GetDisplayMode(ServiceCtx context)
         {
             // TODO: De-hardcode resolution.

+ 3 - 14
Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs

@@ -1,23 +1,12 @@
-using Ryujinx.HLE.HOS.Ipc;
-using System.Collections.Generic;
-
 namespace Ryujinx.HLE.HOS.Services.Vi
 {
     [Service("vi:s")]
     class ISystemRootService : IpcService
     {
-        private Dictionary<int, ServiceProcessRequest> _commands;
-
-        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
-        public ISystemRootService(ServiceCtx context)
-        {
-            _commands = new Dictionary<int, ServiceProcessRequest>
-            {
-                { 1, GetDisplayService }
-            };
-        }
+        public ISystemRootService(ServiceCtx context) { }
 
+        [Command(1)]
+        // GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
         public long GetDisplayService(ServiceCtx context)
         {
             int serviceType = context.RequestData.ReadInt32();