diff --git a/src/LibHac/FsSrv/DefaultFsServerObjects.cs b/src/LibHac/FsSrv/DefaultFsServerObjects.cs index 7adf2fc6..0426a42c 100644 --- a/src/LibHac/FsSrv/DefaultFsServerObjects.cs +++ b/src/LibHac/FsSrv/DefaultFsServerObjects.cs @@ -3,6 +3,7 @@ using LibHac.Common.Keys; using LibHac.FsSrv.FsCreator; using LibHac.FsSrv.Storage; using LibHac.FsSystem; +using LibHac.Gc; using IFileSystem = LibHac.Fs.Fsa.IFileSystem; namespace LibHac.FsSrv; @@ -12,6 +13,7 @@ public class DefaultFsServerObjects public FileSystemCreatorInterfaces FsCreators { get; set; } public EmulatedGameCard GameCard { get; set; } public EmulatedSdCard SdCard { get; set; } + public GameCardDummy GameCardNew { get; set; } public EmulatedStorageDeviceManagerFactory StorageDeviceManagerFactory { get; set; } public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, KeySet keySet, @@ -21,6 +23,8 @@ public class DefaultFsServerObjects var gameCard = new EmulatedGameCard(keySet); var sdCard = new EmulatedSdCard(); + var gameCardNew = new GameCardDummy(); + var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard); using var sharedRootFileSystem = new SharedRef(rootFileSystem); @@ -39,13 +43,14 @@ public class DefaultFsServerObjects creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref); creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, ref sharedRootFileSystemCopy.Ref); - var storageDeviceManagerFactory = new EmulatedStorageDeviceManagerFactory(fsServer, true); + var storageDeviceManagerFactory = new EmulatedStorageDeviceManagerFactory(fsServer, gameCardNew, hasGameCard: true); return new DefaultFsServerObjects { FsCreators = creators, GameCard = gameCard, SdCard = sdCard, + GameCardNew = gameCardNew, StorageDeviceManagerFactory = storageDeviceManagerFactory }; } diff --git a/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs b/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs index 685cac8d..5408019d 100644 --- a/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs +++ b/src/LibHac/FsSrv/Storage/EmulatedStorageDeviceManagerFactory.cs @@ -25,9 +25,10 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory private readonly FileSystemServer _fsServer; private readonly GameCardDummy _gc; - public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, bool hasGameCard) + public EmulatedStorageDeviceManagerFactory(FileSystemServer fsServer, GameCardDummy gc, bool hasGameCard) { _fsServer = fsServer; + _gc = gc; _hasGameCard = hasGameCard; _gameCardDeviceMutex = new SdkMutexType(); @@ -110,12 +111,80 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory return ResultFs.StorageDeviceInvalidOperation.Log(); } + public void AwakenAll() + { + EnsureMmcReady(); + _mmcDeviceManager.Get.Awaken().IgnoreResult(); + + using (ScopedLock.Lock(ref _sdCardDeviceMutex)) + { + if (_sdCardDeviceManager.HasValue) + { + _sdCardDeviceManager.Get.Awaken().IgnoreResult(); + } + } + + using (ScopedLock.Lock(ref _gameCardDeviceMutex)) + { + if (_gameCardDeviceManager.HasValue) + { + _gameCardDeviceManager.Get.Awaken().IgnoreResult(); + } + } + } + + public void PutAllToSleep() + { + using (ScopedLock.Lock(ref _gameCardDeviceMutex)) + { + if (_gameCardDeviceManager.HasValue) + { + _gameCardDeviceManager.Get.PutToSleep().IgnoreResult(); + } + } + + using (ScopedLock.Lock(ref _sdCardDeviceMutex)) + { + if (_sdCardDeviceManager.HasValue) + { + _sdCardDeviceManager.Get.PutToSleep().IgnoreResult(); + } + } + + EnsureMmcReady(); + _mmcDeviceManager.Get.PutToSleep().IgnoreResult(); + } + + public void ShutdownAll() + { + using (ScopedLock.Lock(ref _gameCardDeviceMutex)) + { + if (_gameCardDeviceManager.HasValue) + { + _gameCardDeviceManager.Get.Shutdown().IgnoreResult(); + } + } + + using (ScopedLock.Lock(ref _sdCardDeviceMutex)) + { + if (_sdCardDeviceManager.HasValue) + { + _sdCardDeviceManager.Get.Shutdown().IgnoreResult(); + } + } + + EnsureMmcReady(); + _mmcDeviceManager.Get.Shutdown().IgnoreResult(); + } + private void EnsureMmcReady() { using ScopedLock scopedLock = ScopedLock.Lock(ref _mmcDeviceMutex); if (!_mmcDeviceManager.HasValue) { + // Missing: Register device address space + _mmcDeviceManager.Reset(new MmcManager()); } } diff --git a/src/LibHac/FsSystem/CardDeviceDetectionEvent.cs b/src/LibHac/FsSystem/CardDeviceDetectionEvent.cs index df86e661..edf2dd61 100644 --- a/src/LibHac/FsSystem/CardDeviceDetectionEvent.cs +++ b/src/LibHac/FsSystem/CardDeviceDetectionEvent.cs @@ -1,12 +1,18 @@ using System; using System.Collections.Generic; using LibHac.Common; +using LibHac.Diag; +using LibHac.Fs; using LibHac.FsSrv.Sf; using LibHac.Os; using LibHac.Sf; namespace LibHac.FsSystem; +/// +/// Base class for classes that manage registering events and signaling them when a card device is inserted or removed. +/// +/// Based on nnSdk 14.3.0 (FS 14.1.0) internal class CardDeviceDetectionEventManager : IDisposable { private LinkedList _events; @@ -28,29 +34,55 @@ internal class CardDeviceDetectionEventManager : IDisposable CallbackArgs = new CallbackArguments { EventManager = this, Mutex = _mutex }; } - public virtual void Dispose() - { - throw new NotImplementedException(); - } + public virtual void Dispose() { } public Result CreateDetectionEvent(ref SharedRef outDetectionEvent) { - throw new NotImplementedException(); + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + var detectionEventImpl = new CardDeviceDetectionEvent(this); + using var detectionEvent = new SharedRef(detectionEventImpl); + + if (!detectionEvent.HasValue) + return ResultFs.AllocationMemoryFailedInDeviceDetectionEventManagerA.Log(); + + _events.AddLast(detectionEventImpl); + outDetectionEvent.SetByMove(ref detectionEvent.Ref ); + + return Result.Success; } public void Unlink(CardDeviceDetectionEvent detectionEvent) { - throw new NotImplementedException(); + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + _events.Remove(detectionEvent); } public void SignalAll() { - throw new NotImplementedException(); + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + // ReSharper disable once UnusedVariable + foreach (CardDeviceDetectionEvent detectionEvent in _events) + { + // Todo: Signal event + } } protected static void DetectionEventCallback(object args) { - throw new NotImplementedException(); + Abort.DoAbortUnless(args is CallbackArguments, "Invalid device detection callback arguments type."); + + var callbackArgs = (CallbackArguments)args; + + using ScopedLock scopedLock = ScopedLock.Lock(ref callbackArgs.Mutex); + + // ReSharper disable once UnusedVariable + foreach (CardDeviceDetectionEvent detectionEvent in callbackArgs.EventManager._events) + { + // Todo: Signal event + } } } @@ -66,7 +98,8 @@ internal class CardDeviceDetectionEvent : IEventNotifier public void Dispose() { - throw new NotImplementedException(); + _eventManager?.Unlink(this); + _eventManager = null; } public Result GetEventHandle(out NativeHandle handle) diff --git a/src/LibHac/GcSrv/GameCardDetectionEventManager.cs b/src/LibHac/GcSrv/GameCardDetectionEventManager.cs index 5cd2dac0..f081aaa5 100644 --- a/src/LibHac/GcSrv/GameCardDetectionEventManager.cs +++ b/src/LibHac/GcSrv/GameCardDetectionEventManager.cs @@ -1,17 +1,27 @@ -using System; -using LibHac.FsSystem; +using LibHac.FsSystem; +using LibHac.Gc; namespace LibHac.GcSrv; +/// +/// Manages registering events and signaling them when a game card is inserted or removed. +/// +/// Based on nnSdk 14.3.0 (FS 14.1.0) internal class GameCardDetectionEventManager : CardDeviceDetectionEventManager { - public GameCardDetectionEventManager() + private GameCardDummy _gc; + + public GameCardDetectionEventManager(GameCardDummy gc) { - throw new NotImplementedException(); + _gc = gc; + + gc.RegisterDetectionEventCallback(DetectionEventCallback, CallbackArgs); } public override void Dispose() { - throw new NotImplementedException(); + _gc.UnregisterDetectionEventCallback(); + + base.Dispose(); } } \ No newline at end of file diff --git a/src/LibHac/GcSrv/GameCardManager.cs b/src/LibHac/GcSrv/GameCardManager.cs index 7c190ded..1b4f037b 100644 --- a/src/LibHac/GcSrv/GameCardManager.cs +++ b/src/LibHac/GcSrv/GameCardManager.cs @@ -14,7 +14,8 @@ using LibHac.Os; using LibHac.Sf; using static LibHac.Gc.Values; using static LibHac.GcSrv.GameCardDeviceOperator; -using IStorage = LibHac.FsSrv.Sf.IStorage; +using IStorage = LibHac.Fs.IStorage; +using IStorageSf = LibHac.FsSrv.Sf.IStorage; namespace LibHac.GcSrv; @@ -124,7 +125,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG return Result.Success; } - public Result InitializeGcLibrary() + private Result InitializeGcLibrary() { using var writeLock = new UniqueLock(_rwLock); @@ -139,7 +140,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG _gc.Initialize(default, default); // Missing: Register the device buffer - _detectionEventManager = new GameCardDetectionEventManager(); + _detectionEventManager = new GameCardDetectionEventManager(_gc); _isInitialized = true; return Result.Success; @@ -358,7 +359,7 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG return Result.Success; } - public Result OpenStorage(ref SharedRef outStorage, ulong attribute) + public Result OpenStorage(ref SharedRef outStorage, ulong attribute) { Result res = InitializeGcLibrary(); if (res.IsFailure()) return res.Miss(); @@ -375,7 +376,208 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG private Result OpenDeviceImpl(ref SharedRef outStorageDevice, OpenGameCardAttribute attribute) { - throw new NotImplementedException(); + Result res; + using var writeLock = new UniqueLock(_rwLock); + + using var storageDevice = new SharedRef(); + using var baseStorage = new SharedRef(); + + switch (attribute) + { + case OpenGameCardAttribute.ReadOnly: + res = OpenDeviceReadOnly(ref baseStorage.Ref, ref storageDevice.Ref); + if (res.IsFailure()) return res.Miss(); + break; + case OpenGameCardAttribute.SecureReadOnly: + res = OpenDeviceSecureReadOnly(ref baseStorage.Ref, ref storageDevice.Ref); + if (res.IsFailure()) return res.Miss(); + break; + case OpenGameCardAttribute.WriteOnly: + res = OpenDeviceWriteOnly(ref baseStorage.Ref, ref storageDevice.Ref); + if (res.IsFailure()) return res.Miss(); + break; + default: + return ResultFs.InvalidArgument.Log(); + } + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private Result OpenDeviceReadOnly(ref SharedRef outStorage, + ref SharedRef outStorageDevice) + { + Result res = EnsureGameCardNormalMode(out GameCardHandle handle); + if (res.IsFailure()) return res.Miss(); + + res = CreateReadOnlyStorage(ref outStorage); + if (res.IsFailure()) return res.Miss(); + + if (!outStorage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerB.Log(); + + using SharedRef storageDevice = CreateStorageDeviceNonSecure(in outStorage, handle); + if (!storageDevice.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerB.Log(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private Result OpenDeviceSecureReadOnly(ref SharedRef outStorage, + ref SharedRef outStorageDevice) + { + Result res = EnsureGameCardSecureMode(out GameCardHandle handle); + if (res.IsFailure()) return res.Miss(); + + Span currentCardDeviceId = stackalloc byte[GcCardDeviceIdSize]; + Span currentCardImageHash = stackalloc byte[GcCardImageHashSize]; + + res = HandleGameCardAccessResult(_gc.GetCardDeviceId(currentCardDeviceId)); + if (res.IsFailure()) return res.Miss(); + + res = HandleGameCardAccessResult(_gc.GetCardImageHash(currentCardImageHash)); + if (res.IsFailure()) return res.Miss(); + + res = CreateSecureReadOnlyStorage(ref outStorage); + if (res.IsFailure()) return res.Miss(); + + if (!outStorage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerC.Log(); + + using SharedRef storageDevice = + CreateStorageDeviceSecure(in outStorage, handle, currentCardDeviceId, currentCardImageHash); + + if (!storageDevice.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerD.Log(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private Result OpenDeviceWriteOnly(ref SharedRef outStorage, + ref SharedRef outStorageDevice) + { + Result res = EnsureGameCardWriteMode(out GameCardHandle handle); + if (res.IsFailure()) return res.Miss(); + + res = CreateWriteOnlyStorage(ref outStorage); + if (res.IsFailure()) return res.Miss(); + + if (!outStorage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerE.Log(); + + using SharedRef storageDevice = CreateStorageDeviceNonSecure(in outStorage, handle); + if (!storageDevice.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerF.Log(); + + outStorageDevice.SetByMove(ref storageDevice.Ref); + + return Result.Success; + } + + private class DelegatedSubStorage : SubStorage + { + private SharedRef _baseStorageShared; + + public DelegatedSubStorage(ref UniqueRef baseStorage, long offset, long size) + : base(baseStorage.Get, offset, size) + { + _baseStorageShared = SharedRef.Create(ref baseStorage); + } + + public override void Dispose() + { + _baseStorageShared.Destroy(); + + base.Dispose(); + } + } + + private Result CreateReadOnlyStorage(ref SharedRef outStorage) + { + using var storage = new UniqueRef(MakeReadOnlyGameCardStorage()); + if (!storage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerA.Log(); + + Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus)); + if (res.IsFailure()) return res.Miss(); + + long size = cardStatus.SecureAreaOffset; + + outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, 0, size)); + + return Result.Success; + } + + private Result CreateSecureReadOnlyStorage(ref SharedRef outStorage) + { + using var storage = new UniqueRef(MakeReadOnlyGameCardStorage()); + if (!storage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerC.Log(); + + Result res = HandleGameCardAccessResult(_gc.GetCardStatus(out GameCardStatus cardStatus)); + if (res.IsFailure()) return res.Miss(); + + long offset = cardStatus.SecureAreaOffset; + long size = cardStatus.SecureAreaSize; + + outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, offset, size)); + + return Result.Success; + } + + private Result CreateWriteOnlyStorage(ref SharedRef outStorage) + { + using var storage = new UniqueRef(MakeWriteOnlyGameCardStorage()); + if (!storage.HasValue) + return ResultFs.AllocationMemoryFailedInGameCardManagerE.Log(); + + Result res = storage.Get.GetSize(out long size); + if (res.IsFailure()) return res.Miss(); + + outStorage.Reset(new DelegatedSubStorage(ref storage.Ref, 0, size)); + + return Result.Success; + } + + private ReadOnlyGameCardStorage MakeReadOnlyGameCardStorage() + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + return new ReadOnlyGameCardStorage(ref manager.Ref, _gc); + } + + private WriteOnlyGameCardStorage MakeWriteOnlyGameCardStorage() + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + return new WriteOnlyGameCardStorage(ref manager.Ref, _gc); + } + + private SharedRef CreateStorageDeviceNonSecure(in SharedRef baseStorage, + GameCardHandle handle) + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + using SharedRef storageDevice = + GameCardStorageDevice.CreateShared(_gc, ref manager.Ref, in baseStorage, handle); + + return SharedRef.CreateMove(ref storageDevice.Ref); + } + + private SharedRef CreateStorageDeviceSecure(in SharedRef baseStorage, + GameCardHandle handle, ReadOnlySpan cardDeviceId, ReadOnlySpan cardImageHash) + { + using SharedRef manager = SharedRef.Create(in _selfReference); + + using SharedRef storageDevice = GameCardStorageDevice.CreateShared( + _gc, ref manager.Ref, in baseStorage, handle, isSecure: true, cardDeviceId, cardImageHash); + + return SharedRef.CreateMove(ref storageDevice.Ref); } public Result PutToSleep() @@ -956,6 +1158,15 @@ public class GameCardManager : IStorageDeviceManager, IStorageDeviceOperator, IG public void PresetInternalKeys(ReadOnlySpan gameCardKey, ReadOnlySpan gameCardCertificate) { - throw new NotImplementedException(); + if (gameCardKey.IsEmpty || gameCardCertificate.IsEmpty) + { + _fsServer.Hos.Diag.Impl.LogImpl(Log.EmptyModuleName, LogSeverity.Info, "[fs] Warning: skipped nn::gc::PresetInternalKeys\n"u8); + } + else + { + _gc.PresetInternalKeys(gameCardKey, gameCardCertificate); + } + + // Missing: Signal settings-ready event } } \ No newline at end of file diff --git a/src/LibHac/GcSrv/GameCardStorage.cs b/src/LibHac/GcSrv/GameCardStorage.cs index c2da5657..0e2cec6f 100644 --- a/src/LibHac/GcSrv/GameCardStorage.cs +++ b/src/LibHac/GcSrv/GameCardStorage.cs @@ -11,6 +11,10 @@ using IStorageSf = LibHac.FsSrv.Sf.IStorage; namespace LibHac.GcSrv; +/// +/// Provides an interface for reading from the game card. +/// +/// Based on nnSdk 14.3.0 (FS 14.1.0) internal class ReadOnlyGameCardStorage : IStorage { private SharedRef _deviceManager; @@ -90,6 +94,10 @@ internal class ReadOnlyGameCardStorage : IStorage } } +/// +/// Provides an interface for writing to the game card. +/// +/// Based on nnSdk 14.3.0 (FS 14.1.0) internal class WriteOnlyGameCardStorage : IStorage { private SharedRef _deviceManager; @@ -156,13 +164,17 @@ internal class WriteOnlyGameCardStorage : IStorage } } +/// +/// An adapter that provides an interface for a . +/// +/// Based on nnSdk 14.3.0 (FS 14.1.0) internal abstract class GameCardStorageInterfaceAdapter : IStorageSf { private SharedRef _baseStorage; - protected GameCardStorageInterfaceAdapter(ref SharedRef baseStorage) + protected GameCardStorageInterfaceAdapter(in SharedRef baseStorage) { - _baseStorage = SharedRef.CreateMove(ref baseStorage); + _baseStorage = SharedRef.CreateCopy(in baseStorage); } public virtual void Dispose() diff --git a/src/LibHac/GcSrv/GameCardStorageDevice.cs b/src/LibHac/GcSrv/GameCardStorageDevice.cs index 8bc036d8..e40eaca2 100644 --- a/src/LibHac/GcSrv/GameCardStorageDevice.cs +++ b/src/LibHac/GcSrv/GameCardStorageDevice.cs @@ -23,7 +23,7 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage private readonly GameCardDummy _gc; private GameCardStorageDevice(GameCardDummy gc, ref SharedRef manager, - ref SharedRef baseStorage, GameCardHandle handle) : base(ref baseStorage) + in SharedRef baseStorage, GameCardHandle handle) : base(in baseStorage) { _manager = SharedRef.CreateMove(ref manager); _handle = handle; @@ -33,9 +33,9 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage } private GameCardStorageDevice(GameCardDummy gc, ref SharedRef manager, - ref SharedRef baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan cardDeviceId, + in SharedRef baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan cardDeviceId, ReadOnlySpan cardImageHash) - : base(ref baseStorage) + : base(in baseStorage) { Assert.SdkRequiresEqual(cardDeviceId.Length, Values.GcCardDeviceIdSize); Assert.SdkRequiresEqual(cardImageHash.Length, Values.GcCardImageHashSize); @@ -51,9 +51,9 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage } public static SharedRef CreateShared(GameCardDummy gc, - ref SharedRef manager, ref SharedRef baseStorage, GameCardHandle handle) + ref SharedRef manager, in SharedRef baseStorage, GameCardHandle handle) { - var storageDevice = new GameCardStorageDevice(gc, ref manager, ref baseStorage, handle); + var storageDevice = new GameCardStorageDevice(gc, ref manager, in baseStorage, handle); using var sharedStorageDevice = new SharedRef(storageDevice); storageDevice._selfReference.Set(in sharedStorageDevice); @@ -62,10 +62,10 @@ internal class GameCardStorageDevice : GameCardStorageInterfaceAdapter, IStorage } public static SharedRef CreateShared(GameCardDummy gc, - ref SharedRef manager, ref SharedRef baseStorage, GameCardHandle handle, + ref SharedRef manager, in SharedRef baseStorage, GameCardHandle handle, bool isSecure, ReadOnlySpan cardDeviceId, ReadOnlySpan cardImageHash) { - var storageDevice = new GameCardStorageDevice(gc, ref manager, ref baseStorage, handle, isSecure, cardDeviceId, + var storageDevice = new GameCardStorageDevice(gc, ref manager, in baseStorage, handle, isSecure, cardDeviceId, cardImageHash); using var sharedStorageDevice = new SharedRef(storageDevice); diff --git a/src/LibHac/SdmmcSrv/MmcManager.cs b/src/LibHac/SdmmcSrv/MmcManager.cs index 1505eb0b..9e2eb601 100644 --- a/src/LibHac/SdmmcSrv/MmcManager.cs +++ b/src/LibHac/SdmmcSrv/MmcManager.cs @@ -47,6 +47,21 @@ public class MmcManager : IStorageDeviceManager throw new NotImplementedException(); } + public Result PutToSleep() + { + throw new NotImplementedException(); + } + + public Result Awaken() + { + throw new NotImplementedException(); + } + + public Result Shutdown() + { + throw new NotImplementedException(); + } + public Result Invalidate() { throw new NotImplementedException(); diff --git a/src/LibHac/SdmmcSrv/SdCardManager.cs b/src/LibHac/SdmmcSrv/SdCardManager.cs index fc313aba..cf8f0496 100644 --- a/src/LibHac/SdmmcSrv/SdCardManager.cs +++ b/src/LibHac/SdmmcSrv/SdCardManager.cs @@ -47,6 +47,21 @@ public class SdCardManager : IStorageDeviceManager throw new NotImplementedException(); } + public Result PutToSleep() + { + throw new NotImplementedException(); + } + + public Result Awaken() + { + throw new NotImplementedException(); + } + + public Result Shutdown() + { + throw new NotImplementedException(); + } + public Result Invalidate() { throw new NotImplementedException();