Diff some more storage related classes with FS 16

This commit is contained in:
Alex Barney 2023-09-12 21:42:01 -07:00
parent e2cbb0898c
commit 213515f06f
17 changed files with 151 additions and 25 deletions

View file

@ -0,0 +1,36 @@
#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace LibHac.Common.FixedArrays;
public struct Array436<T>
{
public const int Length = 436;
private Array256<T> _0;
private Array128<T> _256;
private Array32<T> _384;
private Array20<T> _416;
[UnscopedRef] public ref T this[int i] => ref Items[i];
[UnscopedRef]
public Span<T> Items
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
}
[UnscopedRef]
public readonly ReadOnlySpan<T> ItemsRo
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<T>(in Array436<T> value) => value.ItemsRo;
}

View file

@ -12,7 +12,7 @@ namespace LibHac.Fs;
/// <summary> /// <summary>
/// Contains functions for ensuring that an application's save data exists and is the correct size. /// Contains functions for ensuring that an application's save data exists and is the correct size.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0</remarks> /// <remarks>Based on nnSdk 16.2.0</remarks>
public static class ApplicationSaveDataManagement public static class ApplicationSaveDataManagement
{ {
private const int LeftoverFreeSpaceRequiredForUserAndDeviceSaves = 0x4000; private const int LeftoverFreeSpaceRequiredForUserAndDeviceSaves = 0x4000;

View file

@ -6,7 +6,7 @@ namespace LibHac.Fs.Impl;
/// <summary> /// <summary>
/// Allows getting the current handle for the SD card and checking to see if a provided handle is still valid. /// Allows getting the current handle for the SD card and checking to see if a provided handle is still valid.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
internal class SdHandleManager : IDeviceHandleManager internal class SdHandleManager : IDeviceHandleManager
{ {
// LibHac addition // LibHac addition

View file

@ -8,7 +8,7 @@ namespace LibHac.Fs;
/// <summary> /// <summary>
/// Allows interacting with a <see cref="byte"/> array via the <see cref="IStorage"/> interface. /// Allows interacting with a <see cref="byte"/> array via the <see cref="IStorage"/> interface.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class MemoryStorage : IStorage public class MemoryStorage : IStorage
{ {
private byte[] _buffer; private byte[] _buffer;
@ -25,7 +25,6 @@ public class MemoryStorage : IStorage
Assert.SdkRequiresNotNull(buffer); Assert.SdkRequiresNotNull(buffer);
Assert.SdkRequiresInRange(size, 0, buffer.Length); Assert.SdkRequiresInRange(size, 0, buffer.Length);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
Abort.DoAbortUnless(buffer is null || 0 <= size && size < buffer.Length); Abort.DoAbortUnless(buffer is null || 0 <= size && size < buffer.Length);
_buffer = buffer; _buffer = buffer;

View file

@ -16,7 +16,7 @@ namespace LibHac.FsSrv.FsCreator;
/// <summary> /// <summary>
/// Reads the root partition of a game card and handles opening the various partitions it contains. /// Reads the root partition of a game card and handles opening the various partitions it contains.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class GameCardRootPartition : IDisposable public class GameCardRootPartition : IDisposable
{ {
private const int LogoPartitionSizeMax = 0x12000; private const int LogoPartitionSizeMax = 0x12000;
@ -209,7 +209,7 @@ public class GameCardRootPartition : IDisposable
/// <summary> /// <summary>
/// Creates <see cref="IFileSystem"/>s of the various partitions contained by the currently mounted game card. /// Creates <see cref="IFileSystem"/>s of the various partitions contained by the currently mounted game card.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class GameCardFileSystemCreator : IGameCardFileSystemCreator public class GameCardFileSystemCreator : IGameCardFileSystemCreator
{ {
private MemoryResource _allocator; private MemoryResource _allocator;

View file

@ -8,7 +8,7 @@ namespace LibHac.FsSrv.FsCreator;
/// <summary> /// <summary>
/// Creates <see cref="IStorage"/>s to the currently mounted game card. /// Creates <see cref="IStorage"/>s to the currently mounted game card.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class GameCardStorageCreator : IGameCardStorageCreator public class GameCardStorageCreator : IGameCardStorageCreator
{ {
// LibHac addition so we can access fssrv::storage functions // LibHac addition so we can access fssrv::storage functions

View file

@ -7,7 +7,7 @@ namespace LibHac.FsSrv.FsCreator;
/// <summary> /// <summary>
/// Creates <see cref="IStorage"/>s for accessing the inserted SD card's storage. /// Creates <see cref="IStorage"/>s for accessing the inserted SD card's storage.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class SdStorageCreator : ISdStorageCreator public class SdStorageCreator : ISdStorageCreator
{ {
// LibHac addition // LibHac addition

View file

@ -9,7 +9,7 @@ namespace LibHac.FsSrv.Storage;
/// Manages setting storage devices as ready or not ready, and allows opening <see cref="IStorageDeviceManager"/>s for /// Manages setting storage devices as ready or not ready, and allows opening <see cref="IStorageDeviceManager"/>s for
/// each storage device. /// each storage device.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public interface IStorageDeviceManagerFactory : IDisposable public interface IStorageDeviceManagerFactory : IDisposable
{ {
Result Create(ref SharedRef<IStorageDeviceManager> outDeviceManager, StorageDevicePortId portId); Result Create(ref SharedRef<IStorageDeviceManager> outDeviceManager, StorageDevicePortId portId);

View file

@ -9,7 +9,7 @@ namespace LibHac.FsSrv.Storage.Sf;
/// Allows reading from or writing to a storage device's storage like an <see cref="IStorage"/>, getting or validating /// Allows reading from or writing to a storage device's storage like an <see cref="IStorage"/>, getting or validating
/// its current handle, and opening an <see cref="IStorageDeviceOperator"/> for the storage device. /// its current handle, and opening an <see cref="IStorageDeviceOperator"/> for the storage device.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public interface IStorageDevice : IStorage public interface IStorageDevice : IStorage
{ {
Result GetHandle(out uint handle); Result GetHandle(out uint handle);

View file

@ -8,7 +8,7 @@ namespace LibHac.FsSrv.Storage.Sf;
/// <summary> /// <summary>
/// Allows getting the current state of a storage device and opening various interfaces to operate on it. /// Allows getting the current state of a storage device and opening various interfaces to operate on it.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public interface IStorageDeviceManager : IDisposable public interface IStorageDeviceManager : IDisposable
{ {
Result IsInserted(out bool isInserted); Result IsInserted(out bool isInserted);

View file

@ -9,7 +9,7 @@ namespace LibHac.FsSrv.Storage.Sf;
/// </summary> /// </summary>
/// <remarks><para>Operation IDs are not common between implementers of the interface. Every implementer will have its own operations /// <remarks><para>Operation IDs are not common between implementers of the interface. Every implementer will have its own operations
/// and expected input data.</para> /// and expected input data.</para>
/// <para>Based on nnSdk 15.3.0 (FS 15.0.0)</para></remarks> /// <para>Based on nnSdk 16.2.0 (FS 16.0.0)</para></remarks>
public interface IStorageDeviceOperator : IDisposable public interface IStorageDeviceOperator : IDisposable
{ {
Result Operate(int operationId); Result Operate(int operationId);

View file

@ -12,7 +12,7 @@ namespace LibHac.FsSystem;
/// <summary> /// <summary>
/// Base class for classes that manage registering events and signaling them when a card device is inserted or removed. /// Base class for classes that manage registering events and signaling them when a card device is inserted or removed.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
internal class CardDeviceDetectionEventManager : IDisposable internal class CardDeviceDetectionEventManager : IDisposable
{ {
private LinkedList<CardDeviceDetectionEvent> _events; private LinkedList<CardDeviceDetectionEvent> _events;

View file

@ -16,7 +16,7 @@ namespace LibHac.FsSystem;
/// </summary> /// </summary>
/// <remarks><para>The original allocator in FS simply calls <c>nn::fs::detail::Allocate</c> and /// <remarks><para>The original allocator in FS simply calls <c>nn::fs::detail::Allocate</c> and
/// <c>nn::fs::detail::Deallocate</c>. In our implementation we use the shared .NET <see cref="ArrayPool{T}"/>.</para> /// <c>nn::fs::detail::Deallocate</c>. In our implementation we use the shared .NET <see cref="ArrayPool{T}"/>.</para>
/// <para>Based on nnSdk 15.3.0 (FS 15.0.0)</para></remarks> /// <para>Based on nnSdk 16.2.0 (FS 16.0.0)</para></remarks>
file sealed class DefaultAllocatorForPartitionFileSystem : MemoryResource file sealed class DefaultAllocatorForPartitionFileSystem : MemoryResource
{ {
public static readonly DefaultAllocatorForPartitionFileSystem Instance = new(); public static readonly DefaultAllocatorForPartitionFileSystem Instance = new();
@ -50,7 +50,7 @@ file sealed class DefaultAllocatorForPartitionFileSystem : MemoryResource
/// Reads a standard partition file system. These files start with "PFS0" and are typically found inside NCAs /// Reads a standard partition file system. These files start with "PFS0" and are typically found inside NCAs
/// or as .nsp files. /// or as .nsp files.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class PartitionFileSystem : PartitionFileSystemCore<PartitionFileSystemMeta, public class PartitionFileSystem : PartitionFileSystemCore<PartitionFileSystemMeta,
Impl.PartitionFileSystemFormat, Impl.PartitionFileSystemFormat,
Impl.PartitionFileSystemFormat.PartitionFileSystemHeaderImpl, Impl.PartitionFileSystemFormat.PartitionFileSystemHeaderImpl,
@ -59,7 +59,7 @@ public class PartitionFileSystem : PartitionFileSystemCore<PartitionFileSystemMe
/// <summary> /// <summary>
/// Reads a hashed partition file system. These files start with "HFS0" and are typically found inside XCIs. /// Reads a hashed partition file system. These files start with "HFS0" and are typically found inside XCIs.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class Sha256PartitionFileSystem : PartitionFileSystemCore<Sha256PartitionFileSystemMeta, public class Sha256PartitionFileSystem : PartitionFileSystemCore<Sha256PartitionFileSystemMeta,
Impl.Sha256PartitionFileSystemFormat, Impl.Sha256PartitionFileSystemFormat,
Impl.PartitionFileSystemFormat.PartitionFileSystemHeaderImpl, Impl.PartitionFileSystemFormat.PartitionFileSystemHeaderImpl,
@ -74,7 +74,7 @@ public class Sha256PartitionFileSystem : PartitionFileSystemCore<Sha256Partition
/// <typeparam name="TFormat">A traits class that provides values used to read and build the metadata.</typeparam> /// <typeparam name="TFormat">A traits class that provides values used to read and build the metadata.</typeparam>
/// <typeparam name="THeader">The type of the header at the beginning of the metadata.</typeparam> /// <typeparam name="THeader">The type of the header at the beginning of the metadata.</typeparam>
/// <typeparam name="TEntry">The type of the entries in the file table in the metadata.</typeparam> /// <typeparam name="TEntry">The type of the entries in the file table in the metadata.</typeparam>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> : IFileSystem public class PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> : IFileSystem
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new() where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
where TFormat : IPartitionFileSystemFormat where TFormat : IPartitionFileSystemFormat
@ -93,7 +93,7 @@ public class PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> : IFil
/// <summary> /// <summary>
/// Provides access to a file from a <see cref="PartitionFileSystemCore{TMetaData,TFormat,THeader,TEntry}"/>. /// Provides access to a file from a <see cref="PartitionFileSystemCore{TMetaData,TFormat,THeader,TEntry}"/>.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
private class PartitionFile : IFile private class PartitionFile : IFile
{ {
private TEntry _partitionEntry; private TEntry _partitionEntry;
@ -337,7 +337,7 @@ public class PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> : IFil
/// </summary> /// </summary>
/// <remarks><para>A <see cref="PartitionFileSystemCore{TMetaData,TFormat,THeader,TEntry}"/> cannot contain any /// <remarks><para>A <see cref="PartitionFileSystemCore{TMetaData,TFormat,THeader,TEntry}"/> cannot contain any
/// subdirectories, so a <see cref="PartitionDirectory"/> will only access the root directory.</para> /// subdirectories, so a <see cref="PartitionDirectory"/> will only access the root directory.</para>
/// <para>Based on nnSdk 15.3.0 (FS 15.0.0)</para></remarks> /// <para>Based on nnSdk 16.2.0 (FS 16.0.0)</para></remarks>
private class PartitionDirectory : IDirectory private class PartitionDirectory : IDirectory
{ {
private int _currentIndex; private int _currentIndex;

View file

@ -59,7 +59,7 @@ namespace LibHac.FsSystem
/// <typeparam name="TFormat">A traits class that provides values used to read and build the metadata.</typeparam> /// <typeparam name="TFormat">A traits class that provides values used to read and build the metadata.</typeparam>
/// <typeparam name="THeader">The type of the header at the beginning of the metadata.</typeparam> /// <typeparam name="THeader">The type of the header at the beginning of the metadata.</typeparam>
/// <typeparam name="TEntry">The type of the entries in the file table in the metadata.</typeparam> /// <typeparam name="TEntry">The type of the entries in the file table in the metadata.</typeparam>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class PartitionFileSystemMetaCore<TFormat, THeader, TEntry> : IDisposable public class PartitionFileSystemMetaCore<TFormat, THeader, TEntry> : IDisposable
where TFormat : IPartitionFileSystemFormat where TFormat : IPartitionFileSystemFormat
where THeader : unmanaged, IPartitionFileSystemHeader where THeader : unmanaged, IPartitionFileSystemHeader
@ -290,7 +290,7 @@ namespace LibHac.FsSystem
/// <summary> /// <summary>
/// Reads the metadata for a <see cref="Sha256PartitionFileSystem"/>. /// Reads the metadata for a <see cref="Sha256PartitionFileSystem"/>.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class Sha256PartitionFileSystemMeta : PartitionFileSystemMetaCore<TFormat, THeader, TFormat.PartitionEntry> public class Sha256PartitionFileSystemMeta : PartitionFileSystemMetaCore<TFormat, THeader, TFormat.PartitionEntry>
{ {
public Result Initialize(IStorage baseStorage, MemoryResource allocator, ReadOnlySpan<byte> hash) public Result Initialize(IStorage baseStorage, MemoryResource allocator, ReadOnlySpan<byte> hash)
@ -360,7 +360,7 @@ namespace LibHac.FsSystem
/// <summary> /// <summary>
/// Reads the metadata for a <see cref="PartitionFileSystem"/>. /// Reads the metadata for a <see cref="PartitionFileSystem"/>.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 15.3.0 (FS 15.0.0)</remarks> /// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
public class PartitionFileSystemMeta : PartitionFileSystemMetaCore<PartitionFileSystemFormat, public class PartitionFileSystemMeta : PartitionFileSystemMetaCore<PartitionFileSystemFormat,
PartitionFileSystemFormat.PartitionFileSystemHeaderImpl, PartitionFileSystemFormat.PartitionEntry> { } PartitionFileSystemFormat.PartitionFileSystemHeaderImpl, PartitionFileSystemFormat.PartitionEntry> { }
} }

View file

@ -277,7 +277,7 @@ public sealed class GameCardEmulated : IGcApi
int limArea = (int)_cardHeader.LimAreaPage; int limArea = (int)_cardHeader.LimAreaPage;
bool isNormal = pageAddress < limArea; bool isNormal = pageAddress < limArea;
bool isSecure = (pageAddress + pageCount - 1) >= limArea; bool isSecure = pageAddress + pageCount - 1 >= limArea;
// Reads cannot span the boundary between the normal area and secure area. // Reads cannot span the boundary between the normal area and secure area.
if (isNormal && isSecure) if (isNormal && isSecure)

View file

@ -1,4 +1,5 @@
using LibHac.Common.FixedArrays; using System.Runtime.InteropServices;
using LibHac.Common.FixedArrays;
namespace LibHac.Gc.Impl; namespace LibHac.Gc.Impl;
@ -22,9 +23,60 @@ public struct CardId3
public Array4<byte> Reserved; public Array4<byte> Reserved;
} }
public enum DevCardRomSize : byte
{
// ReSharper disable InconsistentNaming
Size1GB = 3,
Size2GB = 4,
Size4GB = 5,
Size8GB = 6,
Size16GB = 7,
Size32GB = 8
// ReSharper restore InconsistentNaming
}
public enum DevCardNandSize : byte
{
// ReSharper disable InconsistentNaming
Size16GB = 7,
Size32GB = 8,
Size64GB = 9
// ReSharper restore InconsistentNaming
}
[StructLayout(LayoutKind.Sequential)]
public struct DevCardParameter public struct DevCardParameter
{ {
public Array512<byte> Data; public CardId1 CardId1;
public CardId2 CardId2;
public CardId3 CardId3;
public uint RomAreaStartAddr;
public uint BackupAreaStartAddr;
public Array3<byte> ReservedAreaStartAddr;
public DevCardRomSize RomSize;
public Array2<byte> WaitCycle1ForRead;
public Array2<byte> WaitCycle2ForRead;
public byte SpeedChangeEmulateWaitCycle1FrequencyForRead;
public Array3<byte> SpeedChangeEmulateWaitCycle1ForRead;
public byte SpeedChangeEmulateWaitCycle2FrequencyForRead;
public Array3<byte> SpeedChangeEmulateWaitCycle2ForRead;
public Array3<byte> FirstReadPageWaitCycleForRead;
public Array2<byte> WaitCycle1ForWrite;
public Array3<byte> WaitCycle2ForWrite;
public byte SpeedChangeEmulateWaitCycle1FrequencyForWrite;
public Array3<byte> SpeedChangeEmulateWaitCycle1ForWrite;
public byte SpeedChangeEmulateWaitCycle2FrequencyForWrite;
public Array3<byte> SpeedChangeEmulateWaitCycle2ForWrite;
public Array2<byte> WaitCycle1ForSetAccessPattern;
public Array3<byte> WaitCycle2ForSetAccessPattern;
public Array3<byte> WaitCycleForRefresh;
public Array3<byte> WaitCycleForSetKey;
public Array3<byte> WaitCycleForIRdInit;
public Array3<byte> WaitCycleForISetInit1;
public Array3<byte> WaitCycleForISetGen;
public Array3<byte> WaitCycleForISetInit2;
public DevCardNandSize NandSize;
public Array436<byte> Reserved;
} }
public struct CardInitialDataPayload public struct CardInitialDataPayload

View file

@ -101,6 +101,45 @@ public class TypeLayoutTests
Assert.Equal(0x30, GetOffset(in s, in s.AuthNonce)); Assert.Equal(0x30, GetOffset(in s, in s.AuthNonce));
} }
[Fact]
public static void DevCardParameter_Layout()
{
var s = new DevCardParameter();
Assert.Equal(0x200, Unsafe.SizeOf<DevCardParameter>());
Assert.Equal(0x00, GetOffset(in s, in s.CardId1));
Assert.Equal(0x04, GetOffset(in s, in s.CardId2));
Assert.Equal(0x08, GetOffset(in s, in s.CardId3));
Assert.Equal(0x0C, GetOffset(in s, in s.RomAreaStartAddr));
Assert.Equal(0x10, GetOffset(in s, in s.BackupAreaStartAddr));
Assert.Equal(0x14, GetOffset(in s, in s.ReservedAreaStartAddr));
Assert.Equal(0x17, GetOffset(in s, in s.RomSize));
Assert.Equal(0x18, GetOffset(in s, in s.WaitCycle1ForRead));
Assert.Equal(0x1A, GetOffset(in s, in s.WaitCycle2ForRead));
Assert.Equal(0x1C, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle1FrequencyForRead));
Assert.Equal(0x1D, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle1ForRead));
Assert.Equal(0x20, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle2FrequencyForRead));
Assert.Equal(0x21, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle2ForRead));
Assert.Equal(0x24, GetOffset(in s, in s.FirstReadPageWaitCycleForRead));
Assert.Equal(0x27, GetOffset(in s, in s.WaitCycle1ForWrite));
Assert.Equal(0x29, GetOffset(in s, in s.WaitCycle2ForWrite));
Assert.Equal(0x2C, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle1FrequencyForWrite));
Assert.Equal(0x2D, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle1ForWrite));
Assert.Equal(0x30, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle2FrequencyForWrite));
Assert.Equal(0x31, GetOffset(in s, in s.SpeedChangeEmulateWaitCycle2ForWrite));
Assert.Equal(0x34, GetOffset(in s, in s.WaitCycle1ForSetAccessPattern));
Assert.Equal(0x36, GetOffset(in s, in s.WaitCycle2ForSetAccessPattern));
Assert.Equal(0x39, GetOffset(in s, in s.WaitCycleForRefresh));
Assert.Equal(0x3C, GetOffset(in s, in s.WaitCycleForSetKey));
Assert.Equal(0x3F, GetOffset(in s, in s.WaitCycleForIRdInit));
Assert.Equal(0x42, GetOffset(in s, in s.WaitCycleForISetInit1));
Assert.Equal(0x45, GetOffset(in s, in s.WaitCycleForISetGen));
Assert.Equal(0x48, GetOffset(in s, in s.WaitCycleForISetInit2));
Assert.Equal(0x4B, GetOffset(in s, in s.NandSize));
Assert.Equal(0x4C, GetOffset(in s, in s.Reserved));
}
[Fact] [Fact]
public static void CardInitialData_Layout() public static void CardInitialData_Layout()
{ {