Implement most of sdmmcsrv

This commit is contained in:
Alex Barney 2022-07-06 14:49:34 -07:00
parent 99d497ca7c
commit 4ffc834427
15 changed files with 1539 additions and 143 deletions

View file

@ -189,7 +189,8 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
{
// Missing: Register device address space
_mmcDeviceManager.Reset(new MmcManager());
using SharedRef<MmcManager> mmcManager = MmcManager.CreateShared(_sdmmc);
_mmcDeviceManager.SetByMove(ref mmcManager.Ref);
}
}
@ -199,7 +200,8 @@ public class EmulatedStorageDeviceManagerFactory : IStorageDeviceManagerFactory
if (!_sdCardDeviceManager.HasValue)
{
_sdCardDeviceManager.Reset(new SdCardManager(_sdmmc));
using SharedRef<SdCardManager> manager = SdCardManager.CreateShared(_sdmmc);
_sdCardDeviceManager.SetByMove(ref manager.Ref);
// Todo: BuiltInStorageFileSystemCreator::SetSdCardPortReady
}

View file

@ -7,7 +7,7 @@ namespace LibHac.FsSrv.Storage.Sf;
// StorageServiceObjectAdapter is a template that is used with either IStorage or IStorageDevice
public interface IStorageDevice : IStorage
{
Result GetHandle(out GameCardHandle handle);
Result GetHandle(out uint handle);
Result IsHandleValid(out bool isValid);
Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator);

View file

@ -36,6 +36,11 @@ public class SdkMutex : ILockable
{
return _mutex.IsLockedByCurrentThread();
}
public ref SdkMutexType GetBase()
{
return ref _mutex;
}
}
public struct SdkMutexType : ILockable

View file

@ -26,7 +26,7 @@ public static class UniqueLock
}
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
public static unsafe ref UniqueLockRef<T> Ref<T>(this in UniqueLockRef<T> value) where T : struct, ILockable
public static unsafe ref UniqueLockRef<T> Ref<T>(this scoped in UniqueLockRef<T> value) where T : struct, ILockable
{
fixed (UniqueLockRef<T>* p = &value)
{
@ -70,7 +70,7 @@ public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
other = default;
}
public void Set(ref UniqueLockRef<TMutex> other)
public void Set(scoped ref UniqueLockRef<TMutex> other)
{
if (_ownsLock)
_mutex.Value.Unlock();

View file

@ -1,8 +1,10 @@
using LibHac.Sdmmc;
using System;
using LibHac.Fs;
using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv;
public static class Common
internal static class Common
{
public static Result CheckConnection(out SpeedMode outSpeedMode, out BusWidth outBusWidth, Port port)
{
@ -12,6 +14,12 @@ public static class Common
return Result.Success;
}
public static Result GetAndClearSdmmcStorageErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
Span<byte> logBuffer, SdmmcApi sdmmc)
{
throw new NotImplementedException();
}
public static uint BytesToSectors(long byteCount)
{
return (uint)((ulong)byteCount / SdmmcApi.SectorSize);

View file

@ -1,54 +1,191 @@
using System;
using LibHac.Common;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.FsSrv.Storage.Sf;
using LibHac.FsSystem;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf;
using static LibHac.Sdmmc.SdmmcApi;
using static LibHac.SdmmcSrv.SdmmcResultConverter;
using MmcPartition = LibHac.Sdmmc.MmcPartition;
namespace LibHac.SdmmcSrv;
internal class MmcDeviceOperator : IStorageDeviceOperator
{
private SharedRef<MmcPartitionStorageDevice> _baseDevice;
private SharedRef<MmcPartitionStorageDevice> _storageDevice;
public MmcDeviceOperator(ref SharedRef<MmcPartitionStorageDevice> baseDevice)
// LibHac additions
private readonly SdmmcApi _sdmmc;
public MmcDeviceOperator(ref SharedRef<MmcPartitionStorageDevice> storageDevice, SdmmcApi sdmmc)
{
_baseDevice = SharedRef<MmcPartitionStorageDevice>.CreateMove(ref baseDevice);
_storageDevice = SharedRef<MmcPartitionStorageDevice>.CreateMove(ref storageDevice);
_sdmmc = sdmmc;
}
public void Dispose()
{
_baseDevice.Destroy();
_storageDevice.Destroy();
}
public Result Operate(int operationId)
{
throw new NotImplementedException();
var operation = (MmcOperationIdValue)operationId;
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = _storageDevice.Get.Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
switch (operation)
{
case MmcOperationIdValue.Erase:
{
Port port = _storageDevice.Get.GetPort();
MmcPartition partition = _storageDevice.Get.GetPartition();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, partition));
try
{
res = GetFsResult(port, _sdmmc.EraseMmc(port));
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
finally
{
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, MmcPartition.UserData));
}
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
{
throw new NotImplementedException();
return ResultFs.NotImplemented.Log();
}
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
{
throw new NotImplementedException();
bytesWritten = 0;
var operation = (MmcOperationIdValue)operationId;
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = _storageDevice.Get.Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
Port port = _storageDevice.Get.GetPort();
switch (operation)
{
case MmcOperationIdValue.GetSpeedMode:
{
if (buffer.Size < sizeof(SpeedMode))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetDeviceSpeedMode(out buffer.As<SpeedMode>(), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = sizeof(SpeedMode);
return Result.Success;
}
case MmcOperationIdValue.GetCid:
{
if (buffer.Size < DeviceCidSize)
return ResultFs.InvalidSize.Log();
res = GetFsResult(port, _sdmmc.GetDeviceCid(buffer.Buffer.Slice(0, DeviceCidSize), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = DeviceCidSize;
return Result.Success;
}
case MmcOperationIdValue.GetPartitionSize:
{
if (buffer.Size < sizeof(long))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, GetPartitionCapacity(out uint numSectors, port));
if (res.IsFailure()) return res.Miss();
buffer.As<long>() = numSectors * SectorSize;
bytesWritten = sizeof(long);
return Result.Success;
}
case MmcOperationIdValue.GetExtendedCsd:
{
if (buffer.Size < MmcExtendedCsdSize)
return ResultFs.InvalidSize.Log();
using var pooledBuffer = new PooledBuffer(MmcExtendedCsdSize, MmcExtendedCsdSize);
if (pooledBuffer.GetSize() < MmcExtendedCsdSize)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceB.Log();
res = GetFsResult(port, _sdmmc.GetMmcExtendedCsd(pooledBuffer.GetBuffer(), port));
if (res.IsFailure()) return res.Miss();
pooledBuffer.GetBuffer().Slice(0, MmcExtendedCsdSize).CopyTo(buffer.Buffer);
bytesWritten = MmcExtendedCsdSize;
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWrittenBuffer1, out bytesWrittenBuffer2);
return ResultFs.NotImplemented.Log();
}
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
private Result GetPartitionCapacity(out uint outNumSectors, Port port)
{
UnsafeHelpers.SkipParamInit(out outNumSectors);
switch (_storageDevice.Get.GetPartition())
{
case MmcPartition.UserData:
{
Result res = _sdmmc.GetDeviceMemoryCapacity(out outNumSectors, port);
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
case MmcPartition.BootPartition1:
case MmcPartition.BootPartition2:
{
Result res = _sdmmc.GetMmcBootPartitionCapacity(out outNumSectors, port);
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
}

View file

@ -1,141 +1,399 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage.Sf;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf;
using IStorage = LibHac.FsSrv.Sf.IStorage;
using MmcPartition = LibHac.Fs.MmcPartition;
namespace LibHac.SdmmcSrv;
public class MmcManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager
internal class MmcManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager
{
private Port _port;
private const SdmmcHandle MmcHandle = 1;
private readonly Port _port;
private bool _isInitialized;
private bool _isActivated;
private SdkMutexType _mutex;
private SdkMutex _mutex;
private readonly SdmmcStorage _sdmmcStorage;
private PatrolReader _patrolReader;
public MmcManager()
// LibHac additions
private WeakRef<MmcManager> _selfReference;
private readonly SdmmcApi _sdmmc;
private MmcManager(SdmmcApi sdmmc)
{
throw new NotImplementedException();
_port = Port.Mmc0;
_mutex = new SdkMutex();
_sdmmcStorage = new SdmmcStorage(_port, sdmmc);
_patrolReader = new PatrolReader(_mutex, sdmmc);
_isInitialized = false;
_isActivated = false;
// Missing: Setting the device address space
_sdmmc = sdmmc;
}
public static SharedRef<MmcManager> CreateShared(SdmmcApi sdmmc)
{
var manager = new MmcManager(sdmmc);
using var sharedManager = new SharedRef<MmcManager>(manager);
manager._selfReference.Set(in sharedManager);
return SharedRef<MmcManager>.CreateMove(ref sharedManager.Ref);
}
public void Dispose()
{
throw new NotImplementedException();
_patrolReader?.Dispose();
_patrolReader = null;
_selfReference.Destroy();
}
public void InitializeMmc()
private Result ActivateMmc()
{
throw new NotImplementedException();
InitializeMmc();
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isActivated)
return Result.Success;
Result res = SdmmcResultConverter.GetFsResult(_port, _sdmmc.Activate(_port));
if (res.IsFailure()) return res.Miss();
_patrolReader.Start();
_isActivated = true;
return Result.Success;
}
private void FinalizeMmc()
{
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isInitialized)
_sdmmc.Finalize(_port);
}
private void InitializeMmc()
{
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isInitialized)
return;
_sdmmc.Initialize(_port);
// Missing: Register the device buffer
// Missing: Allocate work buffer
_isInitialized = true;
}
public Result IsInserted(out bool isInserted)
{
throw new NotImplementedException();
isInserted = true;
return Result.Success;
}
public Result IsHandleValid(out bool isValid, SdmmcHandle handle)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out isValid);
using var scopedLock = new UniqueLockRef<SdkMutexType>();
isValid = Lock(ref scopedLock.Ref(), handle).IsSuccess();
return Result.Success;
}
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
{
throw new NotImplementedException();
return ResultFs.UnsupportedOperation.Log();
}
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
{
throw new NotImplementedException();
Result res = ActivateMmc();
if (res.IsFailure()) return res.Miss();
using SharedRef<MmcManager> deviceOperator = SharedRef<MmcManager>.Create(in _selfReference);
if (!deviceOperator.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
return Result.Success;
}
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
{
throw new NotImplementedException();
using var storageDevice = new SharedRef<IStorageDevice>();
Result res = OpenDeviceImpl(ref storageDevice.Ref, attribute);
if (res.IsFailure()) return res.Miss();
outStorageDevice.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
{
throw new NotImplementedException();
using var storageDevice = new SharedRef<IStorageDevice>();
Result res = OpenDeviceImpl(ref storageDevice.Ref, attribute);
if (res.IsFailure()) return res.Miss();
outStorage.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
private Result OpenStorageDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
private Result OpenDeviceImpl(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
{
throw new NotImplementedException();
Result res = ActivateMmc();
if (res.IsFailure()) return res.Miss();
using var storageDevice = new SharedRef<IStorageDevice>();
switch ((MmcPartition)attribute)
{
case MmcPartition.UserData:
{
OpenDeviceUserDataPartition(ref storageDevice.Ref);
break;
}
case MmcPartition.BootPartition1:
{
OpenDeviceBootPartition(MmcPartition.BootPartition1, ref storageDevice.Ref);
break;
}
case MmcPartition.BootPartition2:
{
OpenDeviceBootPartition(MmcPartition.BootPartition2, ref storageDevice.Ref);
break;
}
default:
return ResultFs.InvalidArgument.Log();
}
if (!storageDevice.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outStorageDevice.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
private void OpenDeviceUserDataPartition(ref SharedRef<IStorageDevice> outStorageDevice)
{
using SharedRef<ISdmmcDeviceManager> manager = SharedRef<ISdmmcDeviceManager>.Create(in _selfReference);
using SharedRef<MmcUserDataPartitionStorageDevice> storageDevice =
MmcUserDataPartitionStorageDevice.CreateShared(ref manager.Ref, MmcHandle, _sdmmc);
outStorageDevice.SetByMove(ref storageDevice.Ref);
}
private void OpenDeviceBootPartition(MmcPartition partition, ref SharedRef<IStorageDevice> outStorageDevice)
{
using SharedRef<ISdmmcDeviceManager> manager = SharedRef<ISdmmcDeviceManager>.Create(in _selfReference);
using SharedRef<MmcBootPartitionStorageDevice> storageDevice =
MmcBootPartitionStorageDevice.CreateShared(partition, ref manager.Ref, MmcHandle, _sdmmc);
outStorageDevice.SetByMove(ref storageDevice.Ref);
}
public Result PutToSleep()
{
throw new NotImplementedException();
if (_isInitialized)
_patrolReader.Sleep();
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isInitialized)
_sdmmc.PutMmcToSleep(_port);
return Result.Success;
}
public Result Awaken()
{
throw new NotImplementedException();
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isInitialized)
{
_sdmmc.AwakenMmc(_port);
_patrolReader.Resume();
}
return Result.Success;
}
public Result Shutdown()
{
throw new NotImplementedException();
if (_isInitialized)
_patrolReader.Stop();
FinalizeMmc();
return Result.Success;
}
public Result Invalidate()
{
throw new NotImplementedException();
return ResultFs.UnsupportedOperation.Log();
}
public Result Lock(ref UniqueLockRef<SdkMutexType> outLock, SdmmcHandle handle)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>(ref _mutex.GetBase());
if (handle != MmcHandle)
return ResultFs.PortMmcStorageDeviceInvalidated.Log();
outLock.Set(ref scopedLock.Ref());
return Result.Success;
}
public Fs.IStorage GetStorage()
{
throw new NotImplementedException();
return _sdmmcStorage;
}
public Port GetPort()
{
throw new NotImplementedException();
return _port;
}
public void NotifyCloseStorageDevice(SdmmcHandle handle)
{
throw new NotImplementedException();
}
public void NotifyCloseStorageDevice(SdmmcHandle handle) { }
public Result Operate(int operationId)
{
throw new NotImplementedException();
var operation = (MmcManagerOperationIdValue)operationId;
switch (operation)
{
case MmcManagerOperationIdValue.SuspendControl:
case MmcManagerOperationIdValue.ResumeControl:
return ResultFs.StorageDeviceInvalidOperation.Log();
case MmcManagerOperationIdValue.SuspendPatrol:
{
_patrolReader.Sleep();
return Result.Success;
}
case MmcManagerOperationIdValue.ResumePatrol:
{
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
_patrolReader.Resume();
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
{
throw new NotImplementedException();
return ResultFs.NotImplemented.Log();
}
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
{
throw new NotImplementedException();
bytesWritten = 0;
var operation = (MmcManagerOperationIdValue)operationId;
switch (operation)
{
case MmcManagerOperationIdValue.GetPatrolCount:
{
if (buffer.Size < sizeof(uint))
return ResultFs.InvalidArgument.Log();
Result res = _patrolReader.GetPatrolCount(out buffer.As<uint>());
if (res.IsFailure()) return res.Miss();
bytesWritten = sizeof(uint);
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId)
{
throw new NotImplementedException();
bytesWrittenBuffer1 = 0;
bytesWrittenBuffer2 = 0;
var operation = (MmcManagerOperationIdValue)operationId;
switch (operation)
{
case MmcManagerOperationIdValue.GetAndClearErrorInfo:
{
if (buffer1.Size < Unsafe.SizeOf<StorageErrorInfo>())
return ResultFs.InvalidArgument.Log();
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
Result res = Common.GetAndClearSdmmcStorageErrorInfo(out buffer1.As<StorageErrorInfo>(),
out bytesWrittenBuffer2, buffer2.Buffer, _sdmmc);
if (res.IsFailure()) return res.Miss();
bytesWrittenBuffer1 = Unsafe.SizeOf<StorageErrorInfo>();
return Result.Success;
}
case MmcManagerOperationIdValue.GetAndClearPatrolReadAllocateBufferCount:
{
if (buffer1.Size < sizeof(long))
return ResultFs.InvalidArgument.Log();
if (buffer2.Size < sizeof(long))
return ResultFs.InvalidArgument.Log();
_patrolReader.GetAndClearAllocateCount(out buffer1.As<ulong>(), out buffer2.As<ulong>());
bytesWrittenBuffer1 = sizeof(long);
bytesWrittenBuffer2 = sizeof(long);
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
}

View file

@ -10,20 +10,30 @@ using MmcPartition = LibHac.Sdmmc.MmcPartition;
namespace LibHac.SdmmcSrv;
internal class MmcPartitionStorageDevice : IDisposable
internal abstract class MmcPartitionStorageDevice : IDisposable
{
private SharedRef<ISdmmcDeviceManager> _manager;
private SdmmcHandle _handle;
private MmcPartition _partition;
private readonly SdmmcHandle _handle;
private readonly MmcPartition _partition;
public MmcPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle, MmcPartition partition)
// LibHac addition
protected WeakRef<MmcPartitionStorageDevice> SelfReference;
protected readonly SdmmcApi Sdmmc;
protected MmcPartitionStorageDevice(MmcPartition partition, ref SharedRef<ISdmmcDeviceManager> manager,
SdmmcHandle handle, SdmmcApi sdmmc)
{
_partition = partition;
_manager = SharedRef<ISdmmcDeviceManager>.CreateMove(ref manager);
_handle = handle;
_partition = partition;
Sdmmc = sdmmc;
}
public void Dispose() { }
public void Dispose()
{
_manager.Destroy();
SelfReference.Destroy();
}
public Result GetHandle(out SdmmcHandle handle)
{
@ -41,7 +51,18 @@ internal class MmcPartitionStorageDevice : IDisposable
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
{
throw new NotImplementedException();
using SharedRef<MmcPartitionStorageDevice> storageDevice =
SharedRef<MmcPartitionStorageDevice>.Create(in SelfReference);
using var deviceOperator =
new SharedRef<MmcDeviceOperator>(new MmcDeviceOperator(ref storageDevice.Ref, Sdmmc));
if (!deviceOperator.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
return Result.Success;
}
public Result Lock(ref UniqueLockRef<SdkMutexType> outLock)
@ -63,12 +84,13 @@ internal class MmcPartitionStorageDevice : IDisposable
// The Mmc*PartitionStorageDevice classes inherit both from SdmmcStorageInterfaceAdapter and MmcPartitionStorageDevice
// Because C# doesn't have multiple inheritance, we make a copy of the SdmmcStorageInterfaceAdapter class that inherits
// from MmcPartitionStorageDevice. This class must mirror any changes made to SdmmcStorageInterfaceAdapter.
internal class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDevice, IStorageDevice
internal abstract class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDevice, IStorageDevice
{
private IStorage _baseStorage;
private readonly IStorage _baseStorage;
public MmcPartitionStorageDeviceInterfaceAdapter(IStorage baseStorage, ref SharedRef<ISdmmcDeviceManager> manager,
SdmmcHandle handle, MmcPartition partition) : base(ref manager, handle, partition)
protected MmcPartitionStorageDeviceInterfaceAdapter(IStorage baseStorage, MmcPartition partition,
ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle, SdmmcApi sdmmc)
: base(partition, ref manager, handle, sdmmc)
{
_baseStorage = baseStorage;
}
@ -109,10 +131,22 @@ internal class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDe
internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter
{
public MmcUserDataPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle)
: base(manager.Get.GetStorage(), ref manager, handle, MmcPartition.UserData)
private MmcUserDataPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle,
SdmmcApi sdmmc)
: base(manager.Get.GetStorage(), MmcPartition.UserData, ref manager, handle, sdmmc)
{ }
public static SharedRef<MmcUserDataPartitionStorageDevice> CreateShared(ref SharedRef<ISdmmcDeviceManager> manager,
SdmmcHandle handle, SdmmcApi sdmmc)
{
var storageDevice = new MmcUserDataPartitionStorageDevice(ref manager, handle, sdmmc);
using var sharedStorageDevice = new SharedRef<MmcUserDataPartitionStorageDevice>(storageDevice);
storageDevice.SelfReference.Set(in sharedStorageDevice);
return SharedRef<MmcUserDataPartitionStorageDevice>.CreateMove(ref sharedStorageDevice.Ref);
}
public override Result Read(long offset, OutBuffer destination, long size)
{
using var scopedLock = new UniqueLockRef<SdkMutexType>();
@ -157,12 +191,20 @@ internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInte
internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter
{
private SdmmcApi _sdmmc;
private MmcBootPartitionStorageDevice(Fs.MmcPartition partition, ref SharedRef<ISdmmcDeviceManager> manager,
SdmmcHandle handle, SdmmcApi sdmmc)
: base(manager.Get.GetStorage(), GetPartition(partition), ref manager, handle, sdmmc)
{ }
public MmcBootPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, Fs.MmcPartition partition,
SdmmcHandle handle, SdmmcApi sdmmc) : base(manager.Get.GetStorage(), ref manager, handle, GetPartition(partition))
public static SharedRef<MmcBootPartitionStorageDevice> CreateShared(Fs.MmcPartition partition,
ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle, SdmmcApi sdmmc)
{
_sdmmc = sdmmc;
var storageDevice = new MmcBootPartitionStorageDevice(partition, ref manager, handle, sdmmc);
using var sharedStorageDevice = new SharedRef<MmcBootPartitionStorageDevice>(storageDevice);
storageDevice.SelfReference.Set(in sharedStorageDevice);
return SharedRef<MmcBootPartitionStorageDevice>.CreateMove(ref sharedStorageDevice.Ref);
}
private static MmcPartition GetPartition(Fs.MmcPartition partition)
@ -188,7 +230,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
try
{
@ -199,7 +241,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
}
finally
{
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
}
}
@ -210,7 +252,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
try
{
@ -221,7 +263,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
}
finally
{
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
}
}
@ -236,11 +278,11 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
Port port = GetPort();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, GetPartition()));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(port, GetPartition()));
try
{
res = SdmmcResultConverter.GetFsResult(port, _sdmmc.GetMmcBootPartitionCapacity(out uint numSectors, port));
res = SdmmcResultConverter.GetFsResult(port, Sdmmc.GetMmcBootPartitionCapacity(out uint numSectors, port));
if (res.IsFailure()) return res.Miss();
size = numSectors * SdmmcApi.SectorSize;
@ -249,7 +291,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
}
finally
{
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
}
}
}

View file

@ -1,11 +1,12 @@
using System;
using LibHac.Os;
using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv;
internal class PatrolReader
{
public PatrolReader(SdkMutex mutex)
public PatrolReader(SdkMutex mutex, SdmmcApi sdmmc)
{
throw new NotImplementedException();
}
@ -30,7 +31,7 @@ internal class PatrolReader
throw new NotImplementedException();
}
public void GetAndClearAllocateCount(out long outSuccessCount, out long outFailureCount)
public void GetAndClearAllocateCount(out ulong outSuccessCount, out ulong outFailureCount)
{
throw new NotImplementedException();
}

View file

@ -6,7 +6,7 @@ namespace LibHac.SdmmcSrv;
internal class SdCardDetectionEventManager : CardDeviceDetectionEventManager
{
// LibHac addition
private SdmmcApi _sdmmc;
private readonly SdmmcApi _sdmmc;
public SdCardDetectionEventManager(Port port, SdmmcApi sdmmc)
{

View file

@ -1,7 +1,11 @@
using System;
using LibHac.Common;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Storage.Sf;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf;
using static LibHac.Sdmmc.SdmmcApi;
using static LibHac.SdmmcSrv.SdmmcResultConverter;
namespace LibHac.SdmmcSrv;
@ -9,9 +13,13 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator
{
private SharedRef<SdCardStorageDevice> _storageDevice;
public SdCardDeviceOperator(ref SharedRef<SdCardStorageDevice> storageDevice)
// LibHac additions
private readonly SdmmcApi _sdmmc;
public SdCardDeviceOperator(ref SharedRef<SdCardStorageDevice> storageDevice, SdmmcApi sdmmc)
{
throw new NotImplementedException();
_storageDevice = SharedRef<SdCardStorageDevice>.CreateMove(ref storageDevice);
_sdmmc = sdmmc;
}
public void Dispose()
@ -21,34 +29,123 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator
public Result Operate(int operationId)
{
throw new NotImplementedException();
return ResultFs.NotImplemented.Log();
}
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
{
throw new NotImplementedException();
return ResultFs.NotImplemented.Log();
}
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
{
throw new NotImplementedException();
bytesWritten = 0;
var operation = (SdCardOperationIdValue)operationId;
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = _storageDevice.Get.Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
Port port = _storageDevice.Get.GetPort();
switch (operation)
{
case SdCardOperationIdValue.GetSpeedMode:
{
if (buffer.Size < sizeof(SpeedMode))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetDeviceSpeedMode(out buffer.As<SpeedMode>(), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = sizeof(SpeedMode);
return Result.Success;
}
case SdCardOperationIdValue.GetCid:
{
if (buffer.Size < DeviceCidSize)
return ResultFs.InvalidSize.Log();
res = GetFsResult(port, _sdmmc.GetDeviceCid(buffer.Buffer.Slice(0, DeviceCidSize), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = DeviceCidSize;
return Result.Success;
}
case SdCardOperationIdValue.GetUserAreaNumSectors:
{
if (buffer.Size < sizeof(uint))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetDeviceMemoryCapacity(out buffer.As<uint>(), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = sizeof(uint);
return Result.Success;
}
case SdCardOperationIdValue.GetUserAreaSize:
{
if (buffer.Size < sizeof(long))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetDeviceMemoryCapacity(out uint numSectors, port));
if (res.IsFailure()) return res.Miss();
buffer.As<long>() = numSectors * SectorSize;
bytesWritten = sizeof(long);
return Result.Success;
}
case SdCardOperationIdValue.GetProtectedAreaNumSectors:
{
if (buffer.Size < sizeof(uint))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetSdCardProtectedAreaCapacity(out buffer.As<uint>(), port));
if (res.IsFailure()) return res.Miss();
bytesWritten = sizeof(uint);
return Result.Success;
}
case SdCardOperationIdValue.GetProtectedAreaSize:
{
if (buffer.Size < sizeof(long))
return ResultFs.InvalidArgument.Log();
res = GetFsResult(port, _sdmmc.GetSdCardProtectedAreaCapacity(out uint numSectors, port));
if (res.IsFailure()) return res.Miss();
buffer.As<long>() = numSectors * SectorSize;
bytesWritten = sizeof(long);
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWrittenBuffer1, out bytesWrittenBuffer2);
return ResultFs.NotImplemented.Log();
}
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
}

View file

@ -1,28 +1,56 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage.Sf;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf;
using LibHac.Util;
using IStorage = LibHac.Fs.IStorage;
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
namespace LibHac.SdmmcSrv;
public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager
{
private Port _port;
private const SdmmcHandle InvalidHandle = 0;
private const int OpenCountFinalized = -1;
private readonly Port _port;
private bool _isInitialized;
/// <summary>
/// Tracks how many storage devices are open. A value of -1 indicates that the SD card device
/// has been shut down and won't be opened again.
/// </summary>
private int _openCount;
private SdkMutexType _mutex;
private SdmmcStorage _sdStorage;
private readonly SdmmcStorage _sdStorage;
private SdmmcHandle _handle;
private Optional<SdCardDetectionEventManager> _detectionEventManager;
public SdCardManager(SdmmcApi sdmmc)
// LibHac additions
private WeakRef<SdCardManager> _selfReference;
private readonly SdmmcApi _sdmmc;
private SdCardManager(SdmmcApi sdmmc)
{
_port = Port.SdCard0;
_mutex = new SdkMutexType();
_sdStorage = new SdmmcStorage(_port, sdmmc);
_sdmmc = sdmmc;
}
public static SharedRef<SdCardManager> CreateShared(SdmmcApi sdmmc)
{
var manager = new SdCardManager(sdmmc);
using var sharedManager = new SharedRef<SdCardManager>(manager);
manager._selfReference.Set(in sharedManager);
return SharedRef<SdCardManager>.CreateMove(ref sharedManager.Ref);
}
public void Dispose()
@ -30,120 +58,354 @@ public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdm
if (_detectionEventManager.HasValue)
{
_detectionEventManager.Value.Dispose();
_detectionEventManager = default;
_detectionEventManager.Clear();
}
_selfReference.Destroy();
}
private void DeactivateIfCardRemoved()
{
if (_openCount > 0 && _sdmmc.IsSdCardRemoved(_port))
{
_sdmmc.Deactivate(_port);
_handle++;
_openCount = 0;
}
}
public void InitializeSd()
private bool IsShutDown()
{
throw new NotImplementedException();
return _openCount < 0;
}
private void InitializeSd()
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (_isInitialized)
return;
// Missing: Work buffer management
if (_detectionEventManager.HasValue)
{
_detectionEventManager.Value.Dispose();
_detectionEventManager.Clear();
}
_detectionEventManager.Set(new SdCardDetectionEventManager(_port, _sdmmc));
_isInitialized = true;
}
public Result IsInserted(out bool isInserted)
{
throw new NotImplementedException();
InitializeSd();
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
DeactivateIfCardRemoved();
isInserted = _sdmmc.IsSdCardInserted(_port);
return Result.Success;
}
public Result IsHandleValid(out bool isValid, SdmmcHandle handle)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
isValid = Lock(ref scopedLock.Ref(), handle).IsSuccess();
return Result.Success;
}
public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
{
throw new NotImplementedException();
InitializeSd();
Result res = _detectionEventManager.Value.CreateDetectionEvent(ref outDetectionEvent);
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
{
throw new NotImplementedException();
InitializeSd();
using SharedRef<SdCardManager> deviceOperator = SharedRef<SdCardManager>.Create(in _selfReference);
if (!deviceOperator.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
return Result.Success;
}
public Result OpenDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
{
throw new NotImplementedException();
using var storageDevice = new SharedRef<IStorageDevice>();
Result res = OpenDeviceImpl(ref storageDevice.Ref);
if (res.IsFailure()) return res.Miss();
outStorageDevice.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
public Result OpenStorage(ref SharedRef<IStorage> outStorage, ulong attribute)
public Result OpenStorage(ref SharedRef<IStorageSf> outStorage, ulong attribute)
{
throw new NotImplementedException();
using var storageDevice = new SharedRef<IStorageDevice>();
Result res = OpenDeviceImpl(ref storageDevice.Ref);
if (res.IsFailure()) return res.Miss();
outStorage.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
private Result OpenStorageDevice(ref SharedRef<IStorageDevice> outStorageDevice, ulong attribute)
private Result OpenDeviceImpl(ref SharedRef<IStorageDevice> outStorageDevice)
{
throw new NotImplementedException();
InitializeSd();
Result res = EnsureActivated(out SdmmcHandle handle);
if (res.IsFailure()) return res.Miss();
using SharedRef<ISdmmcDeviceManager> manager = SharedRef<ISdmmcDeviceManager>.Create(in _selfReference);
using SharedRef<SdCardStorageDevice>
storageDevice = SdCardStorageDevice.CreateShared(ref manager.Ref, handle, _sdmmc);
if (!storageDevice.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outStorageDevice.SetByMove(ref storageDevice.Ref);
return Result.Success;
}
private Result EnsureActivated(out SdmmcHandle outHandle)
{
UnsafeHelpers.SkipParamInit(out outHandle);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
DeactivateIfCardRemoved();
if (IsShutDown())
{
outHandle = InvalidHandle;
return Result.Success;
}
// Activate the device if we're the first to open it.
if (_openCount == 0)
{
Result res = SdmmcResultConverter.GetFsResult(_port, _sdmmc.Activate(_port));
if (res.IsFailure()) return res.Miss();
// Increment the handle if this is the first time the device has been activated.
if (_handle == 0)
{
_handle++;
}
if (_openCount++ >= 0)
{
outHandle = _handle;
return Result.Success;
}
outHandle = InvalidHandle;
return Result.Success;
}
// The device has already been activated. Just increment the open count.
_openCount++;
outHandle = _handle;
return Result.Success;
}
public Result PutToSleep()
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_isInitialized)
_sdmmc.PutSdCardToSleep(_port);
return Result.Success;
}
public Result Awaken()
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_isInitialized)
_sdmmc.AwakenSdCard(_port);
return Result.Success;
}
public Result Shutdown()
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_isInitialized)
{
_sdmmc.Deactivate(_port);
_handle++;
_openCount = OpenCountFinalized;
}
return Result.Success;
}
public Result Invalidate()
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_openCount > 0)
{
_sdmmc.Deactivate(_port);
_handle++;
_openCount = 0;
}
return Result.Success;
}
public Result Lock(ref UniqueLockRef<SdkMutexType> outLock, SdmmcHandle handle)
{
throw new NotImplementedException();
InitializeSd();
using var scopedLock = new UniqueLockRef<SdkMutexType>(ref _mutex);
DeactivateIfCardRemoved();
if (handle == InvalidHandle || _handle != handle)
return ResultFs.PortSdCardStorageDeviceInvalidated.Log();
outLock.Set(ref scopedLock.Ref());
return Result.Success;
}
public Fs.IStorage GetStorage()
public IStorage GetStorage()
{
throw new NotImplementedException();
return _sdStorage;
}
public Port GetPort()
{
throw new NotImplementedException();
return _port;
}
public void NotifyCloseStorageDevice(uint handle)
public void NotifyCloseStorageDevice(SdmmcHandle handle)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_handle != handle)
return;
if (_openCount > 0)
{
_openCount--;
if (_openCount == 0)
{
_sdmmc.Deactivate(_port);
_handle++;
}
}
}
public Result Operate(int operationId)
{
throw new NotImplementedException();
var operation = (SdCardManagerOperationIdValue)operationId;
switch (operation)
{
case SdCardManagerOperationIdValue.SuspendControl:
case SdCardManagerOperationIdValue.ResumeControl:
return ResultFs.StorageDeviceInvalidOperation.Log();
case SdCardManagerOperationIdValue.SimulateDetectionEventSignaled:
_detectionEventManager.Value.SignalAll();
return Result.Success;
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId)
{
throw new NotImplementedException();
return ResultFs.NotImplemented.Log();
}
public Result OperateOut(out long bytesWritten, OutBuffer buffer, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId)
{
throw new NotImplementedException();
var operation = (SdCardManagerOperationIdValue)operationId;
bytesWrittenBuffer1 = 0;
bytesWrittenBuffer2 = 0;
switch (operation)
{
case SdCardManagerOperationIdValue.GetAndClearErrorInfo:
{
if (buffer1.Size < Unsafe.SizeOf<StorageErrorInfo>())
return ResultFs.InvalidArgument.Log();
Result res = GetAndClearSdCardErrorInfo(out buffer1.As<StorageErrorInfo>(), out bytesWrittenBuffer2,
buffer2.Buffer);
if (res.IsFailure()) return res.Miss();
bytesWrittenBuffer1 = Unsafe.SizeOf<StorageErrorInfo>();
return Result.Success;
}
default:
return ResultFs.InvalidArgument.Log();
}
}
public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out bytesWritten);
return ResultFs.NotImplemented.Log();
}
private Result GetAndClearSdCardErrorInfo(out StorageErrorInfo outStorageErrorInfo, out long outLogSize,
Span<byte> logBuffer)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
Result res = Common.GetAndClearSdmmcStorageErrorInfo(out outStorageErrorInfo, out outLogSize, logBuffer, _sdmmc);
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
}

View file

@ -1,5 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Storage.Sf;
using LibHac.Os;
using LibHac.Sdmmc;
@ -10,52 +10,112 @@ namespace LibHac.SdmmcSrv;
internal class SdCardStorageDevice : SdmmcStorageInterfaceAdapter, IStorageDevice
{
private SharedRef<ISdmmcDeviceManager> _manager;
private SdmmcHandle _handle;
private readonly SdmmcHandle _handle;
public SdCardStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle)
// LibHac additions
private WeakRef<SdCardStorageDevice> _selfReference;
private readonly SdmmcApi _sdmmc;
private SdCardStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle, SdmmcApi sdmmc)
: base(manager.Get.GetStorage())
{
_manager = SharedRef<ISdmmcDeviceManager>.CreateMove(ref manager);
_handle = handle;
_sdmmc = sdmmc;
}
public static SharedRef<SdCardStorageDevice> CreateShared(ref SharedRef<ISdmmcDeviceManager> manager,
SdmmcHandle handle, SdmmcApi sdmmc)
{
var device = new SdCardStorageDevice(ref manager, handle, sdmmc);
using var sharedDevice = new SharedRef<SdCardStorageDevice>(device);
device._selfReference.Set(in sharedDevice);
return SharedRef<SdCardStorageDevice>.CreateMove(ref sharedDevice.Ref);
}
public override void Dispose()
{
_manager.Get.NotifyCloseStorageDevice(_handle);
_manager.Destroy();
_selfReference.Destroy();
base.Dispose();
}
public Port GetPort()
{
throw new NotImplementedException();
return _manager.Get.GetPort();
}
public Result GetHandle(out uint handle)
public Result GetHandle(out SdmmcHandle handle)
{
throw new NotImplementedException();
handle = _handle;
return Result.Success;
}
public Result IsHandleValid(out bool isValid)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
isValid = Lock(ref scopedLock.Ref()).IsSuccess();
return Result.Success;
}
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator)
{
throw new NotImplementedException();
using SharedRef<SdCardStorageDevice> storageDevice = SharedRef<SdCardStorageDevice>.Create(in _selfReference);
using var deviceOperator =
new SharedRef<SdCardDeviceOperator>(new SdCardDeviceOperator(ref storageDevice.Ref, _sdmmc));
if (!deviceOperator.HasValue)
return ResultFs.AllocationMemoryFailedInSdmmcStorageServiceA.Log();
outDeviceOperator.SetByMove(ref deviceOperator.Ref);
return Result.Success;
}
public Result Lock(ref UniqueLockRef<SdkMutexType> outLock)
{
throw new NotImplementedException();
Result res = _manager.Get.Lock(ref outLock, _handle);
if (res.IsFailure()) return res.Miss();
return Result.Success;
}
public override Result Read(long offset, OutBuffer destination, long size)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
return base.Read(offset, destination, size).Ret();
}
public override Result Write(long offset, InBuffer source, long size)
{
throw new NotImplementedException();
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
return base.Write(offset, source, size).Ret();
}
public override Result GetSize(out long size)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out size);
using var scopedLock = new UniqueLockRef<SdkMutexType>();
Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss();
return base.GetSize(out size).Ret();
}
}

View file

@ -1,4 +1,4 @@
using System;
using LibHac.Fs;
using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv;
@ -22,11 +22,445 @@ public static class SdmmcResultConverter
private static Result GetFsResultFromMmcResult(Result result)
{
throw new NotImplementedException();
if (ResultSdmmc.NoDevice.Includes(result))
return ResultFs.PortMmcNoDevice.LogConverted(result);
if (ResultSdmmc.NotActivated.Includes(result))
return ResultFs.PortMmcNotActivated.LogConverted(result);
if (ResultSdmmc.DeviceRemoved.Includes(result))
return ResultFs.PortMmcDeviceRemoved.LogConverted(result);
if (ResultSdmmc.NotAwakened.Includes(result))
return ResultFs.PortMmcNotAwakened.LogConverted(result);
if (ResultSdmmc.ResponseIndexError.Includes(result))
return ResultFs.PortMmcResponseIndexError.LogConverted(result);
if (ResultSdmmc.ResponseEndBitError.Includes(result))
return ResultFs.PortMmcResponseEndBitError.LogConverted(result);
if (ResultSdmmc.ResponseCrcError.Includes(result))
return ResultFs.PortMmcResponseCrcError.LogConverted(result);
if (ResultSdmmc.ResponseTimeoutError.Includes(result))
return ResultFs.PortMmcResponseTimeoutError.LogConverted(result);
if (ResultSdmmc.DataEndBitError.Includes(result))
return ResultFs.PortMmcDataEndBitError.LogConverted(result);
if (ResultSdmmc.DataCrcError.Includes(result))
return ResultFs.PortMmcDataCrcError.LogConverted(result);
if (ResultSdmmc.DataTimeoutError.Includes(result))
return ResultFs.PortMmcDataTimeoutError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseIndexError.Includes(result))
return ResultFs.PortMmcAutoCommandResponseIndexError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseEndBitError.Includes(result))
return ResultFs.PortMmcAutoCommandResponseEndBitError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseCrcError.Includes(result))
return ResultFs.PortMmcAutoCommandResponseCrcError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseTimeoutError.Includes(result))
return ResultFs.PortMmcAutoCommandResponseTimeoutError.LogConverted(result);
if (ResultSdmmc.CommandCompleteSoftwareTimeout.Includes(result))
return ResultFs.PortMmcCommandCompleteSwTimeout.LogConverted(result);
if (ResultSdmmc.TransferCompleteSoftwareTimeout.Includes(result))
return ResultFs.PortMmcTransferCompleteSwTimeout.LogConverted(result);
if (ResultSdmmc.DeviceStatusAddressOutOfRange.Includes(result))
return ResultFs.PortMmcDeviceStatusAddressOutOfRange.LogConverted(result);
if (ResultSdmmc.DeviceStatusAddressMisaligned.Includes(result))
return ResultFs.PortMmcDeviceStatusAddressMisalign.LogConverted(result);
if (ResultSdmmc.DeviceStatusBlockLenError.Includes(result))
return ResultFs.PortMmcDeviceStatusBlockLenError.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseSeqError.Includes(result))
return ResultFs.PortMmcDeviceStatusEraseSeqError.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseParam.Includes(result))
return ResultFs.PortMmcDeviceStatusEraseParam.LogConverted(result);
if (ResultSdmmc.DeviceStatusWpViolation.Includes(result))
return ResultFs.PortMmcDeviceStatusWpViolation.LogConverted(result);
if (ResultSdmmc.DeviceStatusLockUnlockFailed.Includes(result))
return ResultFs.PortMmcDeviceStatusLockUnlockFailed.LogConverted(result);
if (ResultSdmmc.DeviceStatusComCrcError.Includes(result))
return ResultFs.PortMmcDeviceStatusComCrcError.LogConverted(result);
if (ResultSdmmc.DeviceStatusIllegalCommand.Includes(result))
return ResultFs.PortMmcDeviceStatusIllegalCommand.LogConverted(result);
if (ResultSdmmc.DeviceStatusDeviceEccFailed.Includes(result))
return ResultFs.PortMmcDeviceStatusDeviceEccFailed.LogConverted(result);
if (ResultSdmmc.DeviceStatusCcError.Includes(result))
return ResultFs.PortMmcDeviceStatusCcError.LogConverted(result);
if (ResultSdmmc.DeviceStatusError.Includes(result))
return ResultFs.PortMmcDeviceStatusError.LogConverted(result);
if (ResultSdmmc.DeviceStatusCidCsdOverwrite.Includes(result))
return ResultFs.PortMmcDeviceStatusCidCsdOverwrite.LogConverted(result);
if (ResultSdmmc.DeviceStatusWpEraseSkip.Includes(result))
return ResultFs.PortMmcDeviceStatusWpEraseSkip.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseReset.Includes(result))
return ResultFs.PortMmcDeviceStatusEraseReset.LogConverted(result);
if (ResultSdmmc.DeviceStatusSwitchError.Includes(result))
return ResultFs.PortMmcDeviceStatusSwitchError.LogConverted(result);
if (ResultSdmmc.UnexpectedDeviceState.Includes(result))
return ResultFs.PortMmcUnexpectedDeviceState.LogConverted(result);
if (ResultSdmmc.UnexpectedDeviceCsdValue.Includes(result))
return ResultFs.PortMmcUnexpectedDeviceCsdValue.LogConverted(result);
if (ResultSdmmc.AbortTransactionSoftwareTimeout.Includes(result))
return ResultFs.PortMmcAbortTransactionSwTimeout.LogConverted(result);
if (ResultSdmmc.CommandInhibitCmdSoftwareTimeout.Includes(result))
return ResultFs.PortMmcCommandInhibitCmdSwTimeout.LogConverted(result);
if (ResultSdmmc.CommandInhibitDatSoftwareTimeout.Includes(result))
return ResultFs.PortMmcCommandInhibitDatSwTimeout.LogConverted(result);
if (ResultSdmmc.BusySoftwareTimeout.Includes(result))
return ResultFs.PortMmcBusySwTimeout.LogConverted(result);
if (ResultSdmmc.IssueTuningCommandSoftwareTimeout.Includes(result))
return ResultFs.PortMmcIssueTuningCommandSwTimeout.LogConverted(result);
if (ResultSdmmc.TuningFailed.Includes(result))
return ResultFs.PortMmcTuningFailed.LogConverted(result);
if (ResultSdmmc.MmcInitializationSoftwareTimeout.Includes(result))
return ResultFs.PortMmcMmcInitializationSwTimeout.LogConverted(result);
if (ResultSdmmc.MmcNotSupportExtendedCsd.Includes(result))
return ResultFs.PortMmcMmcNotSupportExtendedCsd.LogConverted(result);
if (ResultSdmmc.UnexpectedMmcExtendedCsdValue.Includes(result))
return ResultFs.PortMmcUnexpectedMmcExtendedCsdValue.LogConverted(result);
if (ResultSdmmc.MmcEraseSoftwareTimeout.Includes(result))
return ResultFs.PortMmcMmcEraseSwTimeout.LogConverted(result);
if (ResultSdmmc.SdCardValidationError.Includes(result))
return ResultFs.PortMmcSdCardValidationError.LogConverted(result);
if (ResultSdmmc.SdCardInitializationSoftwareTimeout.Includes(result))
return ResultFs.PortMmcSdCardInitializationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdCardGetValidRcaSoftwareTimeout.Includes(result))
return ResultFs.PortMmcSdCardGetValidRcaSwTimeout.LogConverted(result);
if (ResultSdmmc.UnexpectedSdCardAcmdDisabled.Includes(result))
return ResultFs.PortMmcUnexpectedSdCardAcmdDisabled.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportSwitchFunctionStatus.Includes(result))
return ResultFs.PortMmcSdCardNotSupportSwitchFunctionStatus.LogConverted(result);
if (ResultSdmmc.UnexpectedSdCardSwitchFunctionStatus.Includes(result))
return ResultFs.PortMmcUnexpectedSdCardSwitchFunctionStatus.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportAccessMode.Includes(result))
return ResultFs.PortMmcSdCardNotSupportAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardNot4BitBusWidthAtUhsIMode.Includes(result))
return ResultFs.PortMmcSdCardNot4BitBusWidthAtUhsIMode.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportSdr104AndSdr50.Includes(result))
return ResultFs.PortMmcSdCardNotSupportSdr104AndSdr50.LogConverted(result);
if (ResultSdmmc.SdCardCannotSwitchAccessMode.Includes(result))
return ResultFs.PortMmcSdCardCannotSwitchedAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardFailedSwitchAccessMode.Includes(result))
return ResultFs.PortMmcSdCardFailedSwitchedAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardUnacceptableCurrentConsumption.Includes(result))
return ResultFs.PortMmcSdCardUnacceptableCurrentConsumption.LogConverted(result);
if (ResultSdmmc.SdCardNotReadyToVoltageSwitch.Includes(result))
return ResultFs.PortMmcSdCardNotReadyToVoltageSwitch.LogConverted(result);
if (ResultSdmmc.SdCardNotCompleteVoltageSwitch.Includes(result))
return ResultFs.PortMmcSdCardNotCompleteVoltageSwitch.LogConverted(result);
if (ResultSdmmc.InternalClockStableSoftwareTimeout.Includes(result))
return ResultFs.PortMmcInternalClockStableSwTimeout.LogConverted(result);
if (ResultSdmmc.SdHostStandardUnknownAutoCmdError.Includes(result))
return ResultFs.PortMmcSdHostStandardUnknownAutoCmdError.LogConverted(result);
if (ResultSdmmc.SdHostStandardUnknownError.Includes(result))
return ResultFs.PortMmcSdHostStandardUnknownError.LogConverted(result);
if (ResultSdmmc.SdmmcDllCalibrationSoftwareTimeout.Includes(result))
return ResultFs.PortMmcSdmmcDllCalibrationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdmmcDllApplicationSoftwareTimeout.Includes(result))
return ResultFs.PortMmcSdmmcDllApplicationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdHostStandardFailSwitchTo18V.Includes(result))
return ResultFs.PortMmcSdHostStandardFailSwitchTo18V.LogConverted(result);
if (ResultSdmmc.NoWaitedInterrupt.Includes(result))
return ResultFs.PortMmcNoWaitedInterrupt.LogConverted(result);
if (ResultSdmmc.WaitInterruptSoftwareTimeout.Includes(result))
return ResultFs.PortMmcWaitInterruptSwTimeout.LogConverted(result);
if (ResultSdmmc.AbortCommandIssued.Includes(result))
return ResultFs.PortMmcAbortCommandIssued.LogConverted(result);
if (ResultSdmmc.NotSupported.Includes(result))
return ResultFs.PortMmcNotSupported.LogConverted(result);
if (ResultSdmmc.NotImplemented.Includes(result))
return ResultFs.PortMmcNotImplemented.LogConverted(result);
return ResultFs.PortMmcUnexpected.LogConverted(result);
}
private static Result GetFsResultFromSdCardResult(Result result)
{
throw new NotImplementedException();
if (ResultSdmmc.NoDevice.Includes(result))
return ResultFs.PortSdCardNoDevice.LogConverted(result);
if (ResultSdmmc.NotActivated.Includes(result))
return ResultFs.PortSdCardNotActivated.LogConverted(result);
if (ResultSdmmc.DeviceRemoved.Includes(result))
return ResultFs.PortSdCardDeviceRemoved.LogConverted(result);
if (ResultSdmmc.NotAwakened.Includes(result))
return ResultFs.PortSdCardNotAwakened.LogConverted(result);
if (ResultSdmmc.ResponseIndexError.Includes(result))
return ResultFs.PortSdCardResponseIndexError.LogConverted(result);
if (ResultSdmmc.ResponseEndBitError.Includes(result))
return ResultFs.PortSdCardResponseEndBitError.LogConverted(result);
if (ResultSdmmc.ResponseCrcError.Includes(result))
return ResultFs.PortSdCardResponseCrcError.LogConverted(result);
if (ResultSdmmc.ResponseTimeoutError.Includes(result))
return ResultFs.PortSdCardResponseTimeoutError.LogConverted(result);
if (ResultSdmmc.DataEndBitError.Includes(result))
return ResultFs.PortSdCardDataEndBitError.LogConverted(result);
if (ResultSdmmc.DataCrcError.Includes(result))
return ResultFs.PortSdCardDataCrcError.LogConverted(result);
if (ResultSdmmc.DataTimeoutError.Includes(result))
return ResultFs.PortSdCardDataTimeoutError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseIndexError.Includes(result))
return ResultFs.PortSdCardAutoCommandResponseIndexError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseEndBitError.Includes(result))
return ResultFs.PortSdCardAutoCommandResponseEndBitError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseCrcError.Includes(result))
return ResultFs.PortSdCardAutoCommandResponseCrcError.LogConverted(result);
if (ResultSdmmc.AutoCommandResponseTimeoutError.Includes(result))
return ResultFs.PortSdCardAutoCommandResponseTimeoutError.LogConverted(result);
if (ResultSdmmc.CommandCompleteSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardCommandCompleteSwTimeout.LogConverted(result);
if (ResultSdmmc.TransferCompleteSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardTransferCompleteSwTimeout.LogConverted(result);
if (ResultSdmmc.DeviceStatusAddressOutOfRange.Includes(result))
return ResultFs.PortSdCardDeviceStatusAddressOutOfRange.LogConverted(result);
if (ResultSdmmc.DeviceStatusAddressMisaligned.Includes(result))
return ResultFs.PortSdCardDeviceStatusAddressMisalign.LogConverted(result);
if (ResultSdmmc.DeviceStatusBlockLenError.Includes(result))
return ResultFs.PortSdCardDeviceStatusBlockLenError.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseSeqError.Includes(result))
return ResultFs.PortSdCardDeviceStatusEraseSeqError.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseParam.Includes(result))
return ResultFs.PortSdCardDeviceStatusEraseParam.LogConverted(result);
if (ResultSdmmc.DeviceStatusWpViolation.Includes(result))
return ResultFs.PortSdCardDeviceStatusWpViolation.LogConverted(result);
if (ResultSdmmc.DeviceStatusLockUnlockFailed.Includes(result))
return ResultFs.PortSdCardDeviceStatusLockUnlockFailed.LogConverted(result);
if (ResultSdmmc.DeviceStatusComCrcError.Includes(result))
return ResultFs.PortSdCardDeviceStatusComCrcError.LogConverted(result);
if (ResultSdmmc.DeviceStatusIllegalCommand.Includes(result))
return ResultFs.PortSdCardDeviceStatusIllegalCommand.LogConverted(result);
if (ResultSdmmc.DeviceStatusDeviceEccFailed.Includes(result))
return ResultFs.PortSdCardDeviceStatusDeviceEccFailed.LogConverted(result);
if (ResultSdmmc.DeviceStatusCcError.Includes(result))
return ResultFs.PortSdCardDeviceStatusCcError.LogConverted(result);
if (ResultSdmmc.DeviceStatusError.Includes(result))
return ResultFs.PortSdCardDeviceStatusError.LogConverted(result);
if (ResultSdmmc.DeviceStatusCidCsdOverwrite.Includes(result))
return ResultFs.PortSdCardDeviceStatusCidCsdOverwrite.LogConverted(result);
if (ResultSdmmc.DeviceStatusWpEraseSkip.Includes(result))
return ResultFs.PortSdCardDeviceStatusWpEraseSkip.LogConverted(result);
if (ResultSdmmc.DeviceStatusEraseReset.Includes(result))
return ResultFs.PortSdCardDeviceStatusEraseReset.LogConverted(result);
if (ResultSdmmc.DeviceStatusSwitchError.Includes(result))
return ResultFs.PortSdCardDeviceStatusSwitchError.LogConverted(result);
if (ResultSdmmc.UnexpectedDeviceState.Includes(result))
return ResultFs.PortSdCardUnexpectedDeviceState.LogConverted(result);
if (ResultSdmmc.UnexpectedDeviceCsdValue.Includes(result))
return ResultFs.PortSdCardUnexpectedDeviceCsdValue.LogConverted(result);
if (ResultSdmmc.AbortTransactionSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardAbortTransactionSwTimeout.LogConverted(result);
if (ResultSdmmc.CommandInhibitCmdSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardCommandInhibitCmdSwTimeout.LogConverted(result);
if (ResultSdmmc.CommandInhibitDatSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardCommandInhibitDatSwTimeout.LogConverted(result);
if (ResultSdmmc.BusySoftwareTimeout.Includes(result))
return ResultFs.PortSdCardBusySwTimeout.LogConverted(result);
if (ResultSdmmc.IssueTuningCommandSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardIssueTuningCommandSwTimeout.LogConverted(result);
if (ResultSdmmc.TuningFailed.Includes(result))
return ResultFs.PortSdCardTuningFailed.LogConverted(result);
if (ResultSdmmc.MmcInitializationSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardMmcInitializationSwTimeout.LogConverted(result);
if (ResultSdmmc.MmcNotSupportExtendedCsd.Includes(result))
return ResultFs.PortSdCardMmcNotSupportExtendedCsd.LogConverted(result);
if (ResultSdmmc.UnexpectedMmcExtendedCsdValue.Includes(result))
return ResultFs.PortSdCardUnexpectedMmcExtendedCsdValue.LogConverted(result);
if (ResultSdmmc.MmcEraseSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardMmcEraseSwTimeout.LogConverted(result);
if (ResultSdmmc.SdCardValidationError.Includes(result))
return ResultFs.PortSdCardSdCardValidationError.LogConverted(result);
if (ResultSdmmc.SdCardInitializationSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardSdCardInitializationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdCardGetValidRcaSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardSdCardGetValidRcaSwTimeout.LogConverted(result);
if (ResultSdmmc.UnexpectedSdCardAcmdDisabled.Includes(result))
return ResultFs.PortSdCardUnexpectedSdCardAcmdDisabled.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportSwitchFunctionStatus.Includes(result))
return ResultFs.PortSdCardSdCardNotSupportSwitchFunctionStatus.LogConverted(result);
if (ResultSdmmc.UnexpectedSdCardSwitchFunctionStatus.Includes(result))
return ResultFs.PortSdCardUnexpectedSdCardSwitchFunctionStatus.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportAccessMode.Includes(result))
return ResultFs.PortSdCardSdCardNotSupportAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardNot4BitBusWidthAtUhsIMode.Includes(result))
return ResultFs.PortSdCardSdCardNot4BitBusWidthAtUhsIMode.LogConverted(result);
if (ResultSdmmc.SdCardNotSupportSdr104AndSdr50.Includes(result))
return ResultFs.PortSdCardSdCardNotSupportSdr104AndSdr50.LogConverted(result);
if (ResultSdmmc.SdCardCannotSwitchAccessMode.Includes(result))
return ResultFs.PortSdCardSdCardCannotSwitchedAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardFailedSwitchAccessMode.Includes(result))
return ResultFs.PortSdCardSdCardFailedSwitchedAccessMode.LogConverted(result);
if (ResultSdmmc.SdCardUnacceptableCurrentConsumption.Includes(result))
return ResultFs.PortSdCardSdCardUnacceptableCurrentConsumption.LogConverted(result);
if (ResultSdmmc.SdCardNotReadyToVoltageSwitch.Includes(result))
return ResultFs.PortSdCardSdCardNotReadyToVoltageSwitch.LogConverted(result);
if (ResultSdmmc.SdCardNotCompleteVoltageSwitch.Includes(result))
return ResultFs.PortSdCardSdCardNotCompleteVoltageSwitch.LogConverted(result);
if (ResultSdmmc.InternalClockStableSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardInternalClockStableSwTimeout.LogConverted(result);
if (ResultSdmmc.SdHostStandardUnknownAutoCmdError.Includes(result))
return ResultFs.PortSdCardSdHostStandardUnknownAutoCmdError.LogConverted(result);
if (ResultSdmmc.SdHostStandardUnknownError.Includes(result))
return ResultFs.PortSdCardSdHostStandardUnknownError.LogConverted(result);
if (ResultSdmmc.SdmmcDllCalibrationSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardSdmmcDllCalibrationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdmmcDllApplicationSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardSdmmcDllApplicationSwTimeout.LogConverted(result);
if (ResultSdmmc.SdHostStandardFailSwitchTo18V.Includes(result))
return ResultFs.PortSdCardSdHostStandardFailSwitchTo18V.LogConverted(result);
if (ResultSdmmc.NoWaitedInterrupt.Includes(result))
return ResultFs.PortSdCardNoWaitedInterrupt.LogConverted(result);
if (ResultSdmmc.WaitInterruptSoftwareTimeout.Includes(result))
return ResultFs.PortSdCardWaitInterruptSwTimeout.LogConverted(result);
if (ResultSdmmc.AbortCommandIssued.Includes(result))
return ResultFs.PortSdCardAbortCommandIssued.LogConverted(result);
if (ResultSdmmc.NotSupported.Includes(result))
return ResultFs.PortSdCardNotSupported.LogConverted(result);
if (ResultSdmmc.NotImplemented.Includes(result))
return ResultFs.PortSdCardNotImplemented.LogConverted(result);
return ResultFs.PortSdCardUnexpected.LogConverted(result);
}
}

View file

@ -1,8 +1,15 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Sdmmc;
using LibHac.Sf;
using LibHac.Util;
using static LibHac.Sdmmc.SdmmcApi;
using static LibHac.SdmmcSrv.Common;
using static LibHac.SdmmcSrv.SdmmcResultConverter;
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
namespace LibHac.SdmmcSrv;
@ -22,33 +29,116 @@ internal class SdmmcStorage : IStorage
public override Result Read(long offset, Span<byte> destination)
{
throw new NotImplementedException();
Assert.SdkRequiresAligned(offset, SectorSize);
Assert.SdkRequiresAligned(destination.Length, SectorSize);
if (destination.Length == 0)
return Result.Success;
// Missing: Allocate a device buffer if the destination buffer is not one
return _sdmmc.Read(destination, _port, BytesToSectors(offset), BytesToSectors(destination.Length)).Ret();
}
public override Result Write(long offset, ReadOnlySpan<byte> source)
{
throw new NotImplementedException();
const int alignment = 0x4000;
Result res;
Assert.SdkRequiresAligned(offset, SectorSize);
Assert.SdkRequiresAligned(source.Length, SectorSize);
if (source.Length == 0)
return Result.Success;
// Missing: Allocate a device buffer if the source buffer is not one
// Check if we have any unaligned data at the head of the source buffer.
long alignedUpOffset = Alignment.AlignUp(offset, alignment);
int unalignedHeadSize = (int)(alignedUpOffset - offset);
int remainingSize = source.Length;
// The start offset must be aligned to 0x4000 bytes. The end offset does not need to be aligned to 0x4000 bytes.
if (alignedUpOffset != offset)
{
// Get the number of bytes that come before the unaligned data.
int paddingSize = alignment - unalignedHeadSize;
// If the end offset is inside the first 0x4000-byte block, don't write past the end offset.
// Otherwise write the entire aligned block.
int writeSize = Math.Min(alignment, paddingSize + source.Length);
using var pooledBuffer = new PooledBuffer(writeSize, alignment);
// Get the number of bytes from source to be written to the aligned buffer, and copy that data to the buffer.
int unalignedSize = writeSize - paddingSize;
source.Slice(0, unalignedSize).CopyTo(pooledBuffer.GetBuffer().Slice(paddingSize));
// Read the current data into the aligned buffer.
res = GetFsResult(_port,
_sdmmc.Read(pooledBuffer.GetBuffer().Slice(0, paddingSize), _port,
BytesToSectors(alignedUpOffset - alignment), BytesToSectors(paddingSize)));
if (res.IsFailure()) return res.Miss();
// Write the aligned buffer.
res = GetFsResult(_port,
_sdmmc.Write(_port, BytesToSectors(alignedUpOffset - alignment), BytesToSectors(writeSize),
pooledBuffer.GetBuffer().Slice(0, writeSize)));
if (res.IsFailure()) return res.Miss();
remainingSize -= unalignedSize;
}
// We've written any unaligned data. Write the remaining aligned data.
if (remainingSize > 0)
{
res = GetFsResult(_port,
_sdmmc.Write(_port, BytesToSectors(alignedUpOffset), BytesToSectors(remainingSize),
source.Slice(unalignedHeadSize, remainingSize)));
if (res.IsFailure()) return res.Miss();
}
return Result.Success;
}
public override Result Flush()
{
throw new NotImplementedException();
return Result.Success;
}
public override Result SetSize(long size)
{
throw new NotImplementedException();
return ResultFs.UnsupportedSetSizeForSdmmcStorage.Log();
}
public override Result GetSize(out long size)
{
throw new NotImplementedException();
UnsafeHelpers.SkipParamInit(out size);
Result res = GetFsResult(_port, _sdmmc.GetDeviceMemoryCapacity(out uint numSectors, _port));
if (res.IsFailure()) return res.Miss();
size = numSectors * SectorSize;
return Result.Success;
}
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
throw new NotImplementedException();
switch (operationId)
{
case OperationId.InvalidateCache:
return Result.Success;
case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer).Clear();
return Result.Success;
default:
return ResultFs.UnsupportedOperateRangeForSdmmcStorage.Log();
}
}
}