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 // 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) if (!_sdCardDeviceManager.HasValue)
{ {
_sdCardDeviceManager.Reset(new SdCardManager(_sdmmc)); using SharedRef<SdCardManager> manager = SdCardManager.CreateShared(_sdmmc);
_sdCardDeviceManager.SetByMove(ref manager.Ref);
// Todo: BuiltInStorageFileSystemCreator::SetSdCardPortReady // 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 // StorageServiceObjectAdapter is a template that is used with either IStorage or IStorageDevice
public interface IStorageDevice : IStorage public interface IStorageDevice : IStorage
{ {
Result GetHandle(out GameCardHandle handle); Result GetHandle(out uint handle);
Result IsHandleValid(out bool isValid); Result IsHandleValid(out bool isValid);
Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator); Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator);

View File

@ -36,6 +36,11 @@ public class SdkMutex : ILockable
{ {
return _mutex.IsLockedByCurrentThread(); return _mutex.IsLockedByCurrentThread();
} }
public ref SdkMutexType GetBase()
{
return ref _mutex;
}
} }
public struct SdkMutexType : ILockable 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 #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) fixed (UniqueLockRef<T>* p = &value)
{ {
@ -70,7 +70,7 @@ public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
other = default; other = default;
} }
public void Set(ref UniqueLockRef<TMutex> other) public void Set(scoped ref UniqueLockRef<TMutex> other)
{ {
if (_ownsLock) if (_ownsLock)
_mutex.Value.Unlock(); _mutex.Value.Unlock();

View File

@ -1,8 +1,10 @@
using LibHac.Sdmmc; using System;
using LibHac.Fs;
using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
public static class Common internal static class Common
{ {
public static Result CheckConnection(out SpeedMode outSpeedMode, out BusWidth outBusWidth, Port port) public static Result CheckConnection(out SpeedMode outSpeedMode, out BusWidth outBusWidth, Port port)
{ {
@ -12,6 +14,12 @@ public static class Common
return Result.Success; 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) public static uint BytesToSectors(long byteCount)
{ {
return (uint)((ulong)byteCount / SdmmcApi.SectorSize); 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.FsSrv.Storage.Sf;
using LibHac.FsSystem;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf; using LibHac.Sf;
using static LibHac.Sdmmc.SdmmcApi;
using static LibHac.SdmmcSrv.SdmmcResultConverter;
using MmcPartition = LibHac.Sdmmc.MmcPartition;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
internal class MmcDeviceOperator : IStorageDeviceOperator 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() public void Dispose()
{ {
_baseDevice.Destroy(); _storageDevice.Destroy();
} }
public Result Operate(int operationId) 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) 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) 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, public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId) 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, public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId) 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, public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId) 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.Common;
using LibHac.Fs;
using LibHac.FsSrv.Sf; using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage.Sf; using LibHac.FsSrv.Storage.Sf;
using LibHac.Os; using LibHac.Os;
using LibHac.Sdmmc; using LibHac.Sdmmc;
using LibHac.Sf; using LibHac.Sf;
using IStorage = LibHac.FsSrv.Sf.IStorage; using IStorage = LibHac.FsSrv.Sf.IStorage;
using MmcPartition = LibHac.Fs.MmcPartition;
namespace LibHac.SdmmcSrv; 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 _isInitialized;
private bool _isActivated; 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() 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) public Result IsInserted(out bool isInserted)
{ {
throw new NotImplementedException(); isInserted = true;
return Result.Success;
} }
public Result IsHandleValid(out bool isValid, SdmmcHandle handle) 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) public Result OpenDetectionEvent(ref SharedRef<IEventNotifier> outDetectionEvent)
{ {
throw new NotImplementedException(); return ResultFs.UnsupportedOperation.Log();
} }
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator) 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) 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) 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() 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() 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() public Result Shutdown()
{ {
throw new NotImplementedException(); if (_isInitialized)
_patrolReader.Stop();
FinalizeMmc();
return Result.Success;
} }
public Result Invalidate() public Result Invalidate()
{ {
throw new NotImplementedException(); return ResultFs.UnsupportedOperation.Log();
} }
public Result Lock(ref UniqueLockRef<SdkMutexType> outLock, SdmmcHandle handle) 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() public Fs.IStorage GetStorage()
{ {
throw new NotImplementedException(); return _sdmmcStorage;
} }
public Port GetPort() public Port GetPort()
{ {
throw new NotImplementedException(); return _port;
} }
public void NotifyCloseStorageDevice(SdmmcHandle handle) public void NotifyCloseStorageDevice(SdmmcHandle handle) { }
{
throw new NotImplementedException();
}
public Result Operate(int operationId) 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) 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) 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, public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId) 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, public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId) 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, public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId) 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; namespace LibHac.SdmmcSrv;
internal class MmcPartitionStorageDevice : IDisposable internal abstract class MmcPartitionStorageDevice : IDisposable
{ {
private SharedRef<ISdmmcDeviceManager> _manager; private SharedRef<ISdmmcDeviceManager> _manager;
private SdmmcHandle _handle; private readonly SdmmcHandle _handle;
private MmcPartition _partition; 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); _manager = SharedRef<ISdmmcDeviceManager>.CreateMove(ref manager);
_handle = handle; _handle = handle;
_partition = partition; Sdmmc = sdmmc;
} }
public void Dispose() { } public void Dispose()
{
_manager.Destroy();
SelfReference.Destroy();
}
public Result GetHandle(out SdmmcHandle handle) public Result GetHandle(out SdmmcHandle handle)
{ {
@ -41,7 +51,18 @@ internal class MmcPartitionStorageDevice : IDisposable
public Result OpenOperator(ref SharedRef<IStorageDeviceOperator> outDeviceOperator) 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) 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 // 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 // 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. // 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, protected MmcPartitionStorageDeviceInterfaceAdapter(IStorage baseStorage, MmcPartition partition,
SdmmcHandle handle, MmcPartition partition) : base(ref manager, handle, partition) ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle, SdmmcApi sdmmc)
: base(partition, ref manager, handle, sdmmc)
{ {
_baseStorage = baseStorage; _baseStorage = baseStorage;
} }
@ -109,10 +131,22 @@ internal class MmcPartitionStorageDeviceInterfaceAdapter : MmcPartitionStorageDe
internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter
{ {
public MmcUserDataPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle) private MmcUserDataPartitionStorageDevice(ref SharedRef<ISdmmcDeviceManager> manager, SdmmcHandle handle,
: base(manager.Get.GetStorage(), ref manager, handle, MmcPartition.UserData) 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) public override Result Read(long offset, OutBuffer destination, long size)
{ {
using var scopedLock = new UniqueLockRef<SdkMutexType>(); using var scopedLock = new UniqueLockRef<SdkMutexType>();
@ -157,12 +191,20 @@ internal class MmcUserDataPartitionStorageDevice : MmcPartitionStorageDeviceInte
internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfaceAdapter 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, public static SharedRef<MmcBootPartitionStorageDevice> CreateShared(Fs.MmcPartition partition,
SdmmcHandle handle, SdmmcApi sdmmc) : base(manager.Get.GetStorage(), ref manager, handle, GetPartition(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) private static MmcPartition GetPartition(Fs.MmcPartition partition)
@ -188,7 +230,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
Result res = Lock(ref scopedLock.Ref()); Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition())); Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
try try
{ {
@ -199,7 +241,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
} }
finally 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()); Result res = Lock(ref scopedLock.Ref());
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), GetPartition())); Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), GetPartition()));
try try
{ {
@ -221,7 +263,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
} }
finally 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(); Port port = GetPort();
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(port, GetPartition())); Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(port, GetPartition()));
try 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(); if (res.IsFailure()) return res.Miss();
size = numSectors * SdmmcApi.SectorSize; size = numSectors * SdmmcApi.SectorSize;
@ -249,7 +291,7 @@ internal class MmcBootPartitionStorageDevice : MmcPartitionStorageDeviceInterfac
} }
finally finally
{ {
Abort.DoAbortUnlessSuccess(_sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData)); Abort.DoAbortUnlessSuccess(Sdmmc.SelectMmcPartition(GetPort(), MmcPartition.UserData));
} }
} }
} }

View File

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

View File

@ -6,7 +6,7 @@ namespace LibHac.SdmmcSrv;
internal class SdCardDetectionEventManager : CardDeviceDetectionEventManager internal class SdCardDetectionEventManager : CardDeviceDetectionEventManager
{ {
// LibHac addition // LibHac addition
private SdmmcApi _sdmmc; private readonly SdmmcApi _sdmmc;
public SdCardDetectionEventManager(Port port, 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.FsSrv.Storage.Sf;
using LibHac.Os;
using LibHac.Sdmmc;
using LibHac.Sf; using LibHac.Sf;
using static LibHac.Sdmmc.SdmmcApi;
using static LibHac.SdmmcSrv.SdmmcResultConverter;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
@ -9,9 +13,13 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator
{ {
private SharedRef<SdCardStorageDevice> _storageDevice; 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() public void Dispose()
@ -21,34 +29,123 @@ internal class SdCardDeviceOperator : IStorageDeviceOperator
public Result Operate(int operationId) public Result Operate(int operationId)
{ {
throw new NotImplementedException(); return ResultFs.NotImplemented.Log();
} }
public Result OperateIn(InBuffer buffer, long offset, long size, int operationId) 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) 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, public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId) 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, public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId) 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, public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId) 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;
using System.Runtime.CompilerServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Sf; using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage.Sf; using LibHac.FsSrv.Storage.Sf;
using LibHac.Os; using LibHac.Os;
using LibHac.Sdmmc; using LibHac.Sdmmc;
using LibHac.Sf; using LibHac.Sf;
using LibHac.Util; using LibHac.Util;
using IStorage = LibHac.Fs.IStorage;
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdmmcDeviceManager 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; 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 SdkMutexType _mutex;
private SdmmcStorage _sdStorage; private readonly SdmmcStorage _sdStorage;
private SdmmcHandle _handle; private SdmmcHandle _handle;
private Optional<SdCardDetectionEventManager> _detectionEventManager; 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; _port = Port.SdCard0;
_mutex = new SdkMutexType(); _mutex = new SdkMutexType();
_sdStorage = new SdmmcStorage(_port, sdmmc); _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() public void Dispose()
@ -30,120 +58,354 @@ public class SdCardManager : IStorageDeviceManager, IStorageDeviceOperator, ISdm
if (_detectionEventManager.HasValue) if (_detectionEventManager.HasValue)
{ {
_detectionEventManager.Value.Dispose(); _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) 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) 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) 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) 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) 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() public Result PutToSleep()
{ {
throw new NotImplementedException(); using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_isInitialized)
_sdmmc.PutSdCardToSleep(_port);
return Result.Success;
} }
public Result Awaken() public Result Awaken()
{ {
throw new NotImplementedException(); using var scopedLock = new UniqueLockRef<SdkMutexType>();
if (_isInitialized)
_sdmmc.AwakenSdCard(_port);
return Result.Success;
} }
public Result Shutdown() 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() 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) 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() 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) 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) 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) 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, public Result OperateOut2(out long bytesWrittenBuffer1, OutBuffer buffer1, out long bytesWrittenBuffer2,
OutBuffer buffer2, int operationId) 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, public Result OperateInOut(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer, long offset, long size,
int operationId) 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, public Result OperateIn2Out(out long bytesWritten, OutBuffer outBuffer, InBuffer inBuffer1, InBuffer inBuffer2,
long offset, long size, int operationId) 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.FsSrv.Storage.Sf;
using LibHac.Os; using LibHac.Os;
using LibHac.Sdmmc; using LibHac.Sdmmc;
@ -10,52 +10,112 @@ namespace LibHac.SdmmcSrv;
internal class SdCardStorageDevice : SdmmcStorageInterfaceAdapter, IStorageDevice internal class SdCardStorageDevice : SdmmcStorageInterfaceAdapter, IStorageDevice
{ {
private SharedRef<ISdmmcDeviceManager> _manager; 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()) : base(manager.Get.GetStorage())
{ {
_manager = SharedRef<ISdmmcDeviceManager>.CreateMove(ref manager); _manager = SharedRef<ISdmmcDeviceManager>.CreateMove(ref manager);
_handle = handle; _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() 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) 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) 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) 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) 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) 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) 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; using LibHac.Sdmmc;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
@ -22,11 +22,445 @@ public static class SdmmcResultConverter
private static Result GetFsResultFromMmcResult(Result result) 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) 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;
using System.Runtime.CompilerServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs; using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Sdmmc; using LibHac.Sdmmc;
using LibHac.Sf; 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; using IStorageSf = LibHac.FsSrv.Sf.IStorage;
namespace LibHac.SdmmcSrv; namespace LibHac.SdmmcSrv;
@ -22,33 +29,116 @@ internal class SdmmcStorage : IStorage
public override Result Read(long offset, Span<byte> destination) 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) 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() public override Result Flush()
{ {
throw new NotImplementedException(); return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSize(long size)
{ {
throw new NotImplementedException(); return ResultFs.UnsupportedSetSizeForSdmmcStorage.Log();
} }
public override Result GetSize(out long size) 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, public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer) 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();
}
} }
} }