2017-05-19 20:28:49 +01:00
|
|
|
// /***************************************************************************
|
2020-02-27 12:31:23 +00:00
|
|
|
// Aaru Data Preservation Suite
|
2016-10-22 22:58:01 +01:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : ExtendedCSD.cs
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
// Component : Device structures decoders.
|
2016-10-22 22:58:01 +01:00
|
|
|
//
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
// Decodes MultiMediaCard extended CSD.
|
2016-10-22 22:58:01 +01:00
|
|
|
//
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// This library is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This library is distributed in the hope that it will be useful, but
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2022-02-18 10:02:39 +00:00
|
|
|
// Copyright © 2011-2022 Natalia Portillo
|
2016-10-22 22:58:01 +01:00
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
2022-11-13 20:38:14 +00:00
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
using System;
|
2017-12-22 02:04:18 +00:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2016-10-22 22:58:01 +01:00
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
2022-11-15 15:58:41 +00:00
|
|
|
namespace Aaru.Decoders.MMC;
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global"),
|
|
|
|
|
SuppressMessage("ReSharper", "UnassignedField.Global"), StructLayout(LayoutKind.Sequential, Pack = 1)]
|
2022-03-06 13:29:37 +00:00
|
|
|
public class ExtendedCSD
|
2016-10-22 22:58:01 +01:00
|
|
|
{
|
2022-03-06 13:29:37 +00:00
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
|
|
|
|
public byte[] Reserved0;
|
|
|
|
|
public byte CommandQueueModeEnable;
|
|
|
|
|
public byte SecureRemovalType;
|
|
|
|
|
public byte ProductStateAwarenessEnablement;
|
|
|
|
|
public uint MaxPreLoadingDataSize;
|
|
|
|
|
public uint PreLoadingDataSize;
|
|
|
|
|
public byte FFUStatus;
|
|
|
|
|
public ushort Reserved1;
|
|
|
|
|
public byte ModeOperationCodes;
|
|
|
|
|
public byte ModeConfig;
|
|
|
|
|
public byte BarrierControl;
|
|
|
|
|
public byte CacheFlushing;
|
|
|
|
|
public byte CacheControl;
|
|
|
|
|
public byte PowerOffNotification;
|
|
|
|
|
public byte PackedCommandFailureIndex;
|
|
|
|
|
public byte PackedCommandStatus;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
|
|
|
|
public byte[] ContextConfiguration;
|
|
|
|
|
public ushort ExtendedPartitionsAttribute;
|
|
|
|
|
public ushort ExceptionEventsStatus;
|
|
|
|
|
public ushort ExceptionEventsControl;
|
|
|
|
|
public byte DyncapNeeded;
|
|
|
|
|
public byte Class6CommandsControl;
|
|
|
|
|
public byte InitializationTimeoutAfterEmulationChange;
|
|
|
|
|
public byte SectorSize;
|
|
|
|
|
public byte SectorSizeEmulation;
|
|
|
|
|
public byte NativeSectorSize;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
|
|
|
|
|
public byte[] VendorSpecific;
|
|
|
|
|
public ushort Reserved2;
|
|
|
|
|
public byte SupportsProgramCxDInDDR;
|
|
|
|
|
public byte PeriodicWakeUp;
|
|
|
|
|
public byte PackageCaseTemperatureControl;
|
|
|
|
|
public byte ProductionStateAwareness;
|
|
|
|
|
public byte BadBlockManagementMode;
|
|
|
|
|
public byte Reserved3;
|
|
|
|
|
public uint EnhancedUserDataStartAddress;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
|
|
|
public byte[] EnhancedUserDataAreaSize;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
|
|
|
|
|
public byte[] GeneralPurposePartitionSize;
|
|
|
|
|
public byte PartitioningSetting;
|
|
|
|
|
public byte PartitionsAttribute;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
|
|
|
public byte[] MaxEnhancedAreaSize;
|
|
|
|
|
public PartitioningSupport PartitioningSupport;
|
|
|
|
|
public byte HPIManagement;
|
|
|
|
|
public byte HWResetFunction;
|
|
|
|
|
public byte EnableBackgroundOperationsHandshake;
|
|
|
|
|
public byte ManuallyStartBackgroundOperations;
|
|
|
|
|
public byte StartSanitizeOperation;
|
|
|
|
|
public byte WriteReliabilityParameterRegister;
|
|
|
|
|
public byte WriteReliabilitySettingRegister;
|
|
|
|
|
public byte RPMBSize;
|
|
|
|
|
public byte FirmwareConfiguration;
|
|
|
|
|
public byte Reserved4;
|
|
|
|
|
public UserAreaWriteProtectionRegister UserAreaWriteProtectionRegister;
|
|
|
|
|
public byte Reserved5;
|
|
|
|
|
public BootAreaWriteProtectionRegister BootAreaWriteProtectionRegister;
|
|
|
|
|
public byte BootWriteProtectionStatus;
|
|
|
|
|
public HighCapacityEraseGroupDefinition HighCapacityEraseGroupDefinition;
|
|
|
|
|
public byte Reserved6;
|
|
|
|
|
public byte BootBusConditions;
|
|
|
|
|
public BootConfigProtection BootConfigProtection;
|
|
|
|
|
public byte PartitionConfiguration;
|
|
|
|
|
public byte Reserved7;
|
|
|
|
|
public byte ErasedMemoryContent;
|
|
|
|
|
public byte Reserved8;
|
|
|
|
|
public byte BusWidth;
|
|
|
|
|
public byte StrobeSupport;
|
|
|
|
|
public byte HighSpeedInterfaceTiming;
|
|
|
|
|
public byte Reserved9;
|
|
|
|
|
public byte PowerClass;
|
|
|
|
|
public byte Reserved10;
|
|
|
|
|
public byte CommandSetRevision;
|
|
|
|
|
public byte Reserved11;
|
|
|
|
|
public byte CommandSet;
|
|
|
|
|
public byte Revision;
|
|
|
|
|
public byte Reserved12;
|
|
|
|
|
public byte Structure;
|
|
|
|
|
public byte Reserved13;
|
|
|
|
|
public DeviceType DeviceType;
|
|
|
|
|
public DriverStrength DriverStrength;
|
|
|
|
|
public byte OutOfInterruptBusyTiming;
|
|
|
|
|
public byte PartitionSwitchingTime;
|
|
|
|
|
public byte PowerClass52_195;
|
|
|
|
|
public byte PowerClass26_195;
|
|
|
|
|
public byte PowerClass52;
|
|
|
|
|
public byte PowerClass26;
|
|
|
|
|
public byte Reserved14;
|
|
|
|
|
public byte MinimumReadPerformance26_4;
|
|
|
|
|
public byte MinimumWritePerformance26_4;
|
|
|
|
|
public byte MinimumReadPerformance26;
|
|
|
|
|
public byte MinimumWritePerformance26;
|
|
|
|
|
public byte MinimumReadPerformance52;
|
|
|
|
|
public byte MinimumWritePerformance52;
|
|
|
|
|
public SecureWriteProtectInformation SecureWriteProtectInformation;
|
|
|
|
|
public uint SectorCount;
|
|
|
|
|
public byte SleepNotificationTimeout;
|
|
|
|
|
public byte SleepAwakeTimeout;
|
|
|
|
|
public byte ProductionStateAwarenessTimeout;
|
|
|
|
|
public byte SleepCurrentVccQ;
|
|
|
|
|
public byte SleepCurrentVcc;
|
|
|
|
|
public byte HighCapacityWriteProtectGroupSize;
|
|
|
|
|
public byte ReliableWriteSectorCount;
|
|
|
|
|
public byte HighCapacityEraseTimeout;
|
|
|
|
|
public byte HighCapacityEraseUnitSize;
|
|
|
|
|
public byte AccessSize;
|
|
|
|
|
public byte BootPartitionSize;
|
|
|
|
|
public byte Reserved15;
|
|
|
|
|
public BootInformation BootInformation;
|
|
|
|
|
public byte SecureTRIMMultiplier;
|
|
|
|
|
public byte SecureEraseMultiplier;
|
|
|
|
|
public SecureFeatureSupport SecureFeatureSupport;
|
|
|
|
|
public byte TRIMMultiplier;
|
|
|
|
|
public byte Reserved16;
|
|
|
|
|
public byte MinimumReadPerformanceDDR52;
|
|
|
|
|
public byte MinimumWritePerformanceDDR52;
|
|
|
|
|
public byte PowerClassDDR200_130;
|
|
|
|
|
public byte PowerClassDDR200_195;
|
|
|
|
|
public byte PowerClassDDR52_195;
|
|
|
|
|
public byte PowerClassDDR52;
|
|
|
|
|
public CacheFlushingPolicy CacheFlushingPolicy;
|
|
|
|
|
public byte InitializationTimeAfterPartition;
|
|
|
|
|
public uint CorrectlyProgrammedSectors;
|
|
|
|
|
public byte BackgroundOperationsStatus;
|
|
|
|
|
public byte PowerOffNotificationTimeout;
|
|
|
|
|
public byte GenericCMD6Timeout;
|
|
|
|
|
public uint CacheSize;
|
|
|
|
|
public byte PowerClassDDR200;
|
|
|
|
|
public ulong FirmwareVersion;
|
|
|
|
|
public ushort DeviceVersion;
|
|
|
|
|
public byte OptimalTrimUnitSize;
|
|
|
|
|
public byte OptimalWriteSize;
|
|
|
|
|
public byte OptimalReadSize;
|
|
|
|
|
public byte PreEOLInformation;
|
|
|
|
|
public byte DeviceLifeEstimationTypeA;
|
|
|
|
|
public byte DeviceLifeEstimationTypeB;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
|
|
|
|
public byte[] VendorHealthReport;
|
|
|
|
|
public uint NumberOfFWSectorsCorrectlyProgrammed;
|
|
|
|
|
public byte Reserved17;
|
|
|
|
|
public byte CMDQueuingDepth;
|
|
|
|
|
public CMDQueuingSupport CMDQueuingSupport;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)]
|
|
|
|
|
public byte[] Reserved18;
|
|
|
|
|
public byte BarrierSupport;
|
|
|
|
|
public uint FFUArgument;
|
|
|
|
|
public byte OperationCodesTimeout;
|
|
|
|
|
public FFUFeatures FFUFeatures;
|
|
|
|
|
public SupportedModes SupportedModes;
|
|
|
|
|
public ExtendedPartitionsSupport ExtendedPartitionsSupport;
|
|
|
|
|
public byte LargeUnitSize;
|
|
|
|
|
public byte ContextManagementCaps;
|
|
|
|
|
public byte TagResourcesSize;
|
|
|
|
|
public byte TagUnitSize;
|
|
|
|
|
public DataTagSupport DataTagSupport;
|
|
|
|
|
public byte MaxPackedWriteCommands;
|
|
|
|
|
public byte MaxPackedReadCommands;
|
|
|
|
|
public BackgroundOperationsSupport BackgroundOperationsSupport;
|
|
|
|
|
public HPIFeatures HPIFeatures;
|
|
|
|
|
public DeviceSupportedCommandSets SupportedCommandSets;
|
|
|
|
|
public byte ExtendedSecurityCommandsError;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
|
|
|
public byte[] Reserved19;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Flags]
|
|
|
|
|
public enum DeviceSupportedCommandSets : byte
|
|
|
|
|
{
|
|
|
|
|
Standard = 1 << 0
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum HPIFeatures : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Supported = 1 << 0, CMD12 = 1 << 1
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum BackgroundOperationsSupport : byte
|
|
|
|
|
{
|
|
|
|
|
Supported = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum DataTagSupport : byte
|
|
|
|
|
{
|
|
|
|
|
Supported = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum ExtendedPartitionsSupport : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
SystemCode = 1 << 0, NonPersistent = 1 << 1
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum SupportedModes : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
FFU = 1 << 0, VendorSpecific = 1 << 1
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum FFUFeatures : byte
|
|
|
|
|
{
|
|
|
|
|
SupportedModeOperationCodes = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum CMDQueuingSupport : byte
|
|
|
|
|
{
|
|
|
|
|
Supported = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum CacheFlushingPolicy : byte
|
|
|
|
|
{
|
|
|
|
|
FIFO = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum SecureFeatureSupport : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Purge = 1 << 0, Defective = 1 << 2, Trim = 1 << 4,
|
|
|
|
|
Sanitize = 1 << 6
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum BootInformation : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Alternative = 1 << 0, DDR = 1 << 1, HighSpeed = 1 << 2
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum SecureWriteProtectInformation : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Supported = 1 << 0, Enabled = 1 << 1
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum DriverStrength : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Type0 = 1 << 0, Type1 = 1 << 1, Type2 = 1 << 2,
|
|
|
|
|
Type3 = 1 << 3, Type4 = 1 << 4
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum DeviceType : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
HS_26 = 1 << 0, HS_52 = 1 << 1, HS_DDR_52 = 1 << 2,
|
|
|
|
|
HS_DDR_52_LV = 1 << 3, HS200_18 = 1 << 4, HS200_12 = 1 << 5,
|
|
|
|
|
HS400_18 = 1 << 6, HS400_12 = 1 << 7
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum BootConfigProtection : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
PowerCycle = 1 << 0, Permanent = 1 << 4
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum HighCapacityEraseGroupDefinition : byte
|
|
|
|
|
{
|
|
|
|
|
Enabled = 1 << 0
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum BootAreaWriteProtectionRegister : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
PowerOn = 1 << 0, PowerOnArea2 = 1 << 1, Permanent = 1 << 2,
|
|
|
|
|
PermanentArea2 = 1 << 3, PermanentDisable = 1 << 4, PowerOnDisable = 1 << 6,
|
|
|
|
|
Selected = 1 << 7
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum UserAreaWriteProtectionRegister : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
ApplyPowerOn = 1 << 0, ApplyPermanent = 1 << 2, DisablePowerOn = 1 << 3,
|
|
|
|
|
DisablePermanent = 1 << 4, DisableWriteProtect = 1 << 6, DisablePassword = 1 << 7
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[Flags]
|
|
|
|
|
public enum PartitioningSupport : byte
|
|
|
|
|
{
|
2022-11-15 15:58:41 +00:00
|
|
|
Supported = 1 << 0, Enhanced = 1 << 1, Extended = 1 << 2
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
|
|
|
|
|
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
|
|
|
|
public static partial class Decoders
|
|
|
|
|
{
|
|
|
|
|
public static ExtendedCSD DecodeExtendedCSD(byte[] response)
|
2020-12-09 20:11:12 +00:00
|
|
|
{
|
2022-03-06 13:29:37 +00:00
|
|
|
if(response?.Length != 512)
|
|
|
|
|
return null;
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
var handle = GCHandle.Alloc(response, GCHandleType.Pinned);
|
|
|
|
|
var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));
|
|
|
|
|
handle.Free();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
return csd;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
public static string PrettifyExtendedCSD(ExtendedCSD csd)
|
|
|
|
|
{
|
|
|
|
|
if(csd == null)
|
|
|
|
|
return null;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
sb.AppendLine("MultiMediaCard Extended Device Specific Data Register:");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
double unit;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.ExtendedSecurityCommandsError != 0)
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tLast extended security error was {0}", csd.ExtendedSecurityCommandsError).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard))
|
|
|
|
|
sb.AppendLine("\tDevice supports standard MMC command set");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(((int)csd.SupportedCommandSets & 0xFE) != 0)
|
|
|
|
|
sb.AppendFormat("\tDevice supports unknown command sets 0x{0:X2}", (int)csd.SupportedCommandSets);
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported))
|
|
|
|
|
sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12) ? "\tDevice implements HPI using CMD12"
|
|
|
|
|
: "\tDevice implements HPI using CMD13");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported))
|
|
|
|
|
sb.AppendLine("\tDevice supports background operations");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tDevice supports a maximum of {0} packed reads and {1} packed writes",
|
|
|
|
|
csd.MaxPackedReadCommands, csd.MaxPackedWriteCommands).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DataTagSupport.HasFlag(DataTagSupport.Supported))
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports Data Tag");
|
|
|
|
|
sb.AppendFormat("\tTags must be in units of {0} sectors", Math.Pow(2, csd.TagUnitSize)).AppendLine();
|
|
|
|
|
sb.AppendFormat("\tTag resources size is {0}.", csd.TagResourcesSize).AppendLine();
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.ContextManagementCaps != 0)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendFormat("\tMax context ID is {0}.", csd.ContextManagementCaps & 0xF).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tLarge unit maximum multiplier is {0}.", ((csd.ContextManagementCaps & 0x70) >> 4) + 1).
|
|
|
|
|
AppendLine();
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tLarge unit size is {0} MiB", csd.LargeUnitSize + 1).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent))
|
|
|
|
|
sb.AppendLine("\tDevice supports non-persistent extended partitions");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode))
|
|
|
|
|
sb.AppendLine("\tDevice supports system code extended partitions");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SupportedModes.HasFlag(SupportedModes.FFU))
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports FFU");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes))
|
2022-03-07 07:36:42 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
// todo public byte ModeOperationCodes
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.OperationCodesTimeout > 0)
|
2020-12-09 20:11:12 +00:00
|
|
|
{
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = Math.Pow(2, csd.OperationCodesTimeout) * 100;
|
|
|
|
|
|
2022-11-13 19:38:02 +00:00
|
|
|
switch(unit)
|
|
|
|
|
{
|
|
|
|
|
case > 1000000:
|
|
|
|
|
sb.
|
|
|
|
|
AppendFormat("\t\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}s",
|
|
|
|
|
unit / 1000000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case > 1000:
|
|
|
|
|
sb.
|
|
|
|
|
AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}ms",
|
|
|
|
|
unit / 1000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.
|
|
|
|
|
AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs",
|
|
|
|
|
unit).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
}
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific))
|
|
|
|
|
sb.AppendLine("\tDevice supports Vendor Specific Mode");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BarrierSupport == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports the barrier command");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported))
|
|
|
|
|
sb.AppendFormat("\tDevice supports command queuing with a depth of {0}", csd.CMDQueuingDepth + 1).
|
2019-11-25 00:54:38 +00:00
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberOfFWSectorsCorrectlyProgrammed).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.DeviceLifeEstimationTypeB)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice used between 0% and 10% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice used between 10% and 20% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice used between 20% and 30% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
sb.AppendLine("\tDevice used between 30% and 40% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
sb.AppendLine("\tDevice used between 40% and 50% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
sb.AppendLine("\tDevice used between 50% and 60% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
sb.AppendLine("\tDevice used between 60% and 70% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
sb.AppendLine("\tDevice used between 70% and 80% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
sb.AppendLine("\tDevice used between 80% and 90% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
sb.AppendLine("\tDevice used between 90% and 100% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.DeviceLifeEstimationTypeA)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice used between 0% and 10% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice used between 10% and 20% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice used between 20% and 30% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
sb.AppendLine("\tDevice used between 30% and 40% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
sb.AppendLine("\tDevice used between 40% and 50% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
sb.AppendLine("\tDevice used between 50% and 60% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
sb.AppendLine("\tDevice used between 60% and 70% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
sb.AppendLine("\tDevice used between 70% and 80% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
sb.AppendLine("\tDevice used between 80% and 90% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
sb.AppendLine("\tDevice used between 90% and 100% of its estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.PreEOLInformation)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice informs it's in good health");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice informs it should be replaced soon");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice informs it should be replace immediately");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.OptimalReadSize == 0)
|
|
|
|
|
sb.AppendLine("\tDevice does not report an optimal read size");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tOptimal read size is {0} KiB", 4 * csd.OptimalReadSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.OptimalWriteSize == 0)
|
|
|
|
|
sb.AppendLine("\tDevice does not report an optimal write size");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tOptimal write size is {0} KiB", 4 * csd.OptimalWriteSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.OptimalTrimUnitSize == 0)
|
|
|
|
|
sb.AppendLine("\tDevice does not report an optimal trim size");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tOptimal trim size is {0} KiB", 4 * Math.Pow(2, csd.OptimalTrimUnitSize - 1)).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tDevice version: {0}", csd.DeviceVersion).AppendLine();
|
|
|
|
|
sb.AppendFormat("\tFirmware version: {0}", csd.FirmwareVersion).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.CacheSize == 0)
|
|
|
|
|
sb.AppendLine("\tDevice has no cache");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize / 8).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.GenericCMD6Timeout > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms by default for a SWITCH command",
|
|
|
|
|
csd.GenericCMD6Timeout * 10).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.PowerOffNotificationTimeout > 0)
|
|
|
|
|
sb.
|
|
|
|
|
AppendFormat("\tDevice takes a maximum of {0} by default to power off from a SWITCH command notification",
|
|
|
|
|
csd.PowerOffNotificationTimeout * 10).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.BackgroundOperationsStatus & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice has no pending background operations");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice has non critical operations outstanding");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice has performance impacted operations outstanding");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice has critical operations outstanding");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tLast WRITE MULTIPLE command correctly programmed {0} sectors",
|
|
|
|
|
csd.CorrectlyProgrammedSectors).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.InitializationTimeAfterPartition > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for initialization after partition",
|
|
|
|
|
csd.InitializationTimeAfterPartition * 100).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO))
|
|
|
|
|
sb.AppendLine("\tDevice uses a FIFO policy for cache flushing");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.TRIMMultiplier > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group",
|
|
|
|
|
csd.TRIMMultiplier * 300).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize))
|
|
|
|
|
sb.AppendLine("\tDevice supports the sanitize operation");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim))
|
|
|
|
|
sb.AppendLine("\tDevice supports supports the secure and insecure trim operations");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective))
|
|
|
|
|
sb.AppendLine("\tDevice supports automatic erase on retired defective blocks");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge))
|
|
|
|
|
sb.AppendLine("\tDevice supports secure purge operations");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureEraseMultiplier > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely erasing a single erase group",
|
|
|
|
|
csd.SecureEraseMultiplier * 300).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureTRIMMultiplier > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely trimming a single erase group",
|
|
|
|
|
csd.SecureTRIMMultiplier * 300).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.HighSpeed))
|
|
|
|
|
sb.AppendLine("\tDevice supports high speed timing on boot");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.DDR))
|
|
|
|
|
sb.AppendLine("\tDevice supports dual data rate on boot");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.Alternative))
|
|
|
|
|
sb.AppendLine("\tDevice supports alternative boot method");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootPartitionSize > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice has a {0} KiB boot partition", csd.BootPartitionSize * 128).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.AccessSize & 0x0F) > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice has a page size of {0} KiB",
|
|
|
|
|
512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.HighCapacityEraseUnitSize > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.HighCapacityEraseTimeout > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for erasing a single erase group",
|
|
|
|
|
csd.HighCapacityEraseTimeout * 300).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.HighCapacityWriteProtectGroupSize > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice smallest write protect group is made of {0} erase groups",
|
|
|
|
|
csd.HighCapacityWriteProtectGroupSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SleepCurrentVcc > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepCurrentVcc);
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(unit > 1000)
|
|
|
|
|
sb.AppendFormat("\tDevice uses {0} mA on Vcc when sleeping", unit / 1000).AppendLine();
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice uses {0} μA on Vcc when sleeping", unit).AppendLine();
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SleepCurrentVccQ > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepCurrentVccQ);
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(unit > 1000)
|
|
|
|
|
sb.AppendFormat("\tDevice uses {0} mA on Vccq when sleeping", unit / 1000).AppendLine();
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice uses {0} μA on Vccq when sleeping", unit).AppendLine();
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.ProductionStateAwarenessTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.ProductionStateAwareness) * 100;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-11-13 19:38:02 +00:00
|
|
|
switch(unit)
|
|
|
|
|
{
|
|
|
|
|
case > 1000000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} s to switch production state awareness",
|
|
|
|
|
unit / 1000000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case > 1000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to switch production state awareness",
|
|
|
|
|
unit / 1000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to switch production state awareness", unit).
|
|
|
|
|
AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SleepAwakeTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepAwakeTimeout) * 100;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-11-13 19:38:02 +00:00
|
|
|
switch(unit)
|
|
|
|
|
{
|
|
|
|
|
case > 1000000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to transition between sleep and standby states",
|
|
|
|
|
unit / 1000000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case > 1000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to transition between sleep and standby states",
|
|
|
|
|
unit / 1000).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ns to transition between sleep and standby states",
|
|
|
|
|
unit).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SleepNotificationTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepNotificationTimeout) * 10;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-11-13 19:38:02 +00:00
|
|
|
switch(unit)
|
|
|
|
|
{
|
|
|
|
|
case > 1000000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} s to move to sleep state", unit / 1000000).
|
|
|
|
|
AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case > 1000:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to move to sleep state", unit / 1000).
|
|
|
|
|
AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to move to sleep state", unit).AppendLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-06 13:29:37 +00:00
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tDevice has {0} sectors", csd.SectorCount).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported))
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports secure write protection");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled))
|
|
|
|
|
sb.AppendLine("\tDevice has secure write protection enabled");
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumReadPerformance26 * 300;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumReadPerformance26 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumReadPerformance26_4 * 300;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumReadPerformance26_4 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode");
|
|
|
|
|
else
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumReadPerformance52 * 300;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumReadPerformance52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 52Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumReadPerformanceDDR52 * 600;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumReadPerformanceDDR52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 4.8MB/s reading in DDR 52Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumWritePerformance26 * 300;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumWritePerformance26 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumWritePerformance26_4 * 300;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumWritePerformance26_4 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode");
|
|
|
|
|
else
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumWritePerformance52 * 300;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumWritePerformance52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 52Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
unit = csd.MinimumWritePerformanceDDR52 * 600;
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.MinimumWritePerformanceDDR52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 4.8MB/s writing in DDR 52Mhz mode");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.PartitionSwitchingTime > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice can take a maximum of {0} ms when switching partitions",
|
|
|
|
|
csd.PartitionSwitchingTime * 10).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.OutOfInterruptBusyTiming > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt",
|
|
|
|
|
csd.OutOfInterruptBusyTiming * 10).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type0))
|
|
|
|
|
sb.AppendLine("\tDevice supports I/O driver strength type 0.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type1))
|
|
|
|
|
sb.AppendLine("\tDevice supports I/O driver strength type 1.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type2))
|
|
|
|
|
sb.AppendLine("\tDevice supports I/O driver strength type 2.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type3))
|
|
|
|
|
sb.AppendLine("\tDevice supports I/O driver strength type 3.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type4))
|
|
|
|
|
sb.AppendLine("\tDevice supports I/O driver strength type 4.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_26))
|
|
|
|
|
sb.AppendLine("\tDevice supports 26 Mhz mode");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_52))
|
|
|
|
|
sb.AppendLine("\tDevice supports 52 Mhz mode");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52))
|
|
|
|
|
sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV))
|
|
|
|
|
sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS200_18))
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS200_12))
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS400_18))
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS400_12))
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.2V");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tCSD version 1.{0} revision 1.{1}", csd.Structure, csd.Revision).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.CommandSet)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice follows compatibility MMC command set.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
switch(csd.CommandSetRevision)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice follows standard MMC command set v4.0.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice follows standard MMC command set with unknown version code {0}.",
|
|
|
|
|
csd.CommandSetRevision).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice follows unknown MMC command set code {0} with revision code {1}.",
|
|
|
|
|
csd.CommandSet, csd.CommandSetRevision).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.HighSpeedInterfaceTiming & 0x0F)
|
|
|
|
|
{
|
|
|
|
|
case 0: break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice is in High Speed mode.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice is in HS-200 mode.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice is in HS-400 mode.");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice has unknown timing mode {0}.", csd.HighSpeedInterfaceTiming & 0x0F).
|
|
|
|
|
AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
sb.AppendFormat("\tSelected driver strength is type {0}.", (csd.HighSpeedInterfaceTiming & 0xF0) >> 4).
|
|
|
|
|
AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.StrobeSupport & 0x01) == 0x01)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports enhanced strobe mode");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendLine((csd.BusWidth & 0x80) == 0x80 ? "\tDevice uses strobe during Data Out, CRC and CMD responses"
|
2022-03-06 13:29:37 +00:00
|
|
|
: "\tDevice uses strobe during Data Out and CRC responses");
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.BusWidth & 0x0F)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is using 1-bit data bus");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice is using 4-bit data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice is using 8-bit data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
sb.AppendLine("\tDevice is using 4-bit DDR data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
sb.AppendLine("\tDevice is using 8-bit DDR data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice is using unknown data bus code {0}", csd.BusWidth & 0x0F).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.ErasedMemoryContent)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendFormat("\tErased memory range shall be '{0}'.", csd.ErasedMemoryContent).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tUnknown erased memory content code {0}", csd.ErasedMemoryContent).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.PartitionConfiguration & 0x40) == 0x40)
|
|
|
|
|
sb.AppendLine("\tDevice sends boot acknowledge");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch((csd.PartitionConfiguration & 0x38) >> 3)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is not boot enabled");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice boot partition 1 is enabled");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice boot partition 2 is enabled");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
sb.AppendLine("\tDevice user area is enable for boot");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tUnknown enabled boot partition code {0}", (csd.PartitionConfiguration & 0x38) >> 3).
|
|
|
|
|
AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.PartitionConfiguration & 0x07)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tThere is no access to boot partition");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to boot partition 1");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to boot partition 2");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to replay protected memory block");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tThere is access to general purpose partition {0}",
|
|
|
|
|
(csd.PartitionConfiguration & 0x07) - 3).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootConfigProtection.HasFlag(BootConfigProtection.Permanent))
|
|
|
|
|
sb.AppendLine("\tChange of the boot configuration register bits is permanently disabled.");
|
|
|
|
|
else if(csd.BootConfigProtection.HasFlag(BootConfigProtection.PowerCycle))
|
|
|
|
|
sb.AppendLine("\tChange of the boot configuration register bits is disabled until the next power cycle.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.BootBusConditions & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice will boot up in x1 SDR or x4 DDR bus width.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice will boot up in x4 SDR or DDR bus width.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice will boot up in x8 SDR or DDR bus width.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tUnknown boot condition for bus width with code 3.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendLine((csd.BootBusConditions & 4) == 4 ? "\tDevice will retain boot conditions after boot operation."
|
2022-03-06 13:29:37 +00:00
|
|
|
: "\tDevice will reset boot conditions to compatibility mode after boot operation.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch((csd.BootBusConditions & 0x24) >> 3)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice will use single data rate with compatible timings in boot operation.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice will use single data rate with high speed timings in boot operation.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice will use dual data rate in boot operation.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice will use unknown boot mode with code 3.");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(csd.HighCapacityEraseGroupDefinition.HasFlag(HighCapacityEraseGroupDefinition.Enabled))
|
|
|
|
|
sb.AppendLine("\tDevice will use high capacity erase unit size, timeout and write protect group size definitions.");
|
|
|
|
|
|
|
|
|
|
switch(csd.BootWriteProtectionStatus & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tBoot area 1 is not protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tBoot area 1 is power on protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tBoot area 1 is permanently protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch((csd.BootWriteProtectionStatus & 0x0C) >> 2)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tBoot area 2 is not protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tBoot area 2 is power on protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tBoot area 2 is permanently protected");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Permanent))
|
|
|
|
|
{
|
|
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected))
|
|
|
|
|
sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.
|
|
|
|
|
PermanentArea2)
|
|
|
|
|
? "\tBoot area 2 is permanently write protected."
|
|
|
|
|
: "\tBoot area 1 is permanently write protected.");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendLine("\tBoth boot areas are permanently write protected.");
|
|
|
|
|
}
|
|
|
|
|
else if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOn))
|
|
|
|
|
{
|
|
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected))
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnArea2)
|
2022-03-06 13:29:37 +00:00
|
|
|
? "\tBoot area 2 is write protected until next power cycle."
|
|
|
|
|
: "\tBoot area 1 is write protected until next power cycle.");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendLine("\tBoth boot areas are write protected until next power cycle.");
|
|
|
|
|
}
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable))
|
|
|
|
|
sb.AppendLine("\tPermanent write protection of boot areas is disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable))
|
|
|
|
|
sb.AppendLine("\tPower cycled write protection of boot areas is disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword))
|
|
|
|
|
sb.AppendLine("\tUse of password protection features is permanently disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect))
|
|
|
|
|
sb.AppendLine("\tUse of permanent write protection is disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent))
|
|
|
|
|
sb.AppendLine("\tPermanent write protection is disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn))
|
|
|
|
|
sb.AppendLine("\tPower cycled write protection is disabled.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent))
|
|
|
|
|
sb.AppendLine("\tPermanent write protection will be applied to selected group.");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn))
|
|
|
|
|
sb.AppendLine("\tPower cycled write protection will be applied to selected group.");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.FirmwareConfiguration & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tFirmware updates are permanently disabled");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.RPMBSize > 0)
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tDevice has a {0} KiB replay protected memory block", csd.RPMBSize * 128).AppendLine();
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported))
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports partitioning features");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced))
|
|
|
|
|
sb.AppendLine("\tDevice can have enhanced technological features in partitions and user data area");
|
2020-12-09 20:11:12 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended))
|
|
|
|
|
sb.AppendLine("\tDevice can have extended partitions attribute.");
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.NativeSectorSize)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice natively uses 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice natively uses 4096 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice natively uses unknown sector size indicated by code {0}",
|
|
|
|
|
csd.NativeSectorSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.SectorSizeEmulation)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is emulating 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice is using natively sized sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
2022-03-07 07:36:42 +00:00
|
|
|
sb.AppendFormat("\tDevice emulates unknown sector size indicated by code {0}", csd.NativeSectorSize).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
switch(csd.SectorSize)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice currently addresses 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice currently addresses 4096 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb.AppendFormat("\tDevice currently addresses unknown sector size indicated by code {0}",
|
|
|
|
|
csd.NativeSectorSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.CacheControl & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice's cache is enabled");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
if((csd.CommandQueueModeEnable & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice has enabled command queuing");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2022-03-06 13:29:37 +00:00
|
|
|
return sb.ToString();
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
2022-03-06 13:29:37 +00:00
|
|
|
|
|
|
|
|
public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response));
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|