2017-05-19 20:28:49 +01:00
|
|
|
// /***************************************************************************
|
2016-10-22 22:58:01 +01:00
|
|
|
// The Disc Image Chef
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// 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/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2020-01-03 17:51:28 +00:00
|
|
|
// Copyright © 2011-2020 Natalia Portillo
|
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;
|
|
|
|
|
|
2020-02-27 00:33:24 +00:00
|
|
|
namespace Aaru.Decoders.MMC
|
2016-10-22 22:58:01 +01:00
|
|
|
{
|
2019-11-25 00:54:38 +00:00
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
|
|
|
|
|
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"),
|
|
|
|
|
StructLayout(LayoutKind.Sequential)]
|
2016-10-22 22:58:01 +01:00
|
|
|
public class ExtendedCSD
|
|
|
|
|
{
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte AccessSize;
|
|
|
|
|
public byte AddressedGroupToBeReleased;
|
|
|
|
|
public byte BackgroundOperationsStatus;
|
2016-10-22 22:58:01 +01:00
|
|
|
public byte BackgroundOperationsSupport;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte BadBlockManagementMode;
|
|
|
|
|
public byte BarrierControl;
|
2016-10-22 22:58:01 +01:00
|
|
|
public byte BarrierSupport;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte BootAreaWriteProtectionRegister;
|
|
|
|
|
public byte BootBusConditions;
|
|
|
|
|
public byte BootConfigProtection;
|
|
|
|
|
public byte BootInformation;
|
|
|
|
|
public byte BootPartitionSize;
|
|
|
|
|
public byte BootWriteProtectionStatus;
|
|
|
|
|
public byte BusWidth;
|
|
|
|
|
public byte CacheControl;
|
|
|
|
|
public byte CacheFlushing;
|
|
|
|
|
public byte CacheFlushingPolicy;
|
|
|
|
|
public uint CacheSize;
|
|
|
|
|
public byte Class6CommandsControl;
|
2016-10-22 22:58:01 +01:00
|
|
|
public byte CMDQueuingDepth;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte CMDQueuingSupport;
|
|
|
|
|
public byte CommandQueueModeEnable;
|
|
|
|
|
public byte CommandSet;
|
|
|
|
|
public byte CommandSetRevision;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
|
|
|
|
public byte[] ContextConfiguration;
|
|
|
|
|
public byte ContextManagementCaps;
|
|
|
|
|
public uint CorrectlyProgrammedSectors;
|
|
|
|
|
public byte DataTagSupport;
|
2018-06-22 08:08:38 +01:00
|
|
|
public byte DeviceLifeEstimationTypeA;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte DeviceLifeEstimationTypeB;
|
|
|
|
|
public byte DeviceType;
|
2016-10-22 22:58:01 +01:00
|
|
|
public ushort DeviceVersion;
|
2018-06-22 08:08:38 +01:00
|
|
|
public byte DriverStrength;
|
|
|
|
|
public byte EnableBackgroundOperationsHandshake;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
|
|
|
public byte[] EnhancedUserDataAreaSize;
|
|
|
|
|
public uint EnhancedUserDataStartAddress;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte ErasedMemoryContent;
|
2016-10-22 22:58:01 +01:00
|
|
|
public ushort ExceptionEventsControl;
|
|
|
|
|
public ushort ExceptionEventsStatus;
|
|
|
|
|
public ushort ExtendedPartitionsAttribute;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte ExtendedPartitionsSupport;
|
|
|
|
|
public byte ExtendedSecurityCommandsError;
|
|
|
|
|
public uint FFUArgument;
|
|
|
|
|
public byte FFUFeatures;
|
2018-06-22 08:08:38 +01:00
|
|
|
public byte FFUStatus;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte FirmwareConfiguration;
|
|
|
|
|
public ulong FirmwareVersion;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
|
|
|
|
|
public byte[] GeneralPurposePartitionSize;
|
|
|
|
|
public byte GenericCMD6Timeout;
|
|
|
|
|
public byte HighCapacityEraseTimeout;
|
|
|
|
|
public byte HighCapacityEraseUnitSize;
|
|
|
|
|
public byte HighCapacityWriteProtectGroupSize;
|
|
|
|
|
public byte HighDensityEraseGroupDefinition;
|
|
|
|
|
public byte HighSpeedInterfaceTiming;
|
|
|
|
|
public byte HPIFeatures;
|
|
|
|
|
public byte HPIManagement;
|
|
|
|
|
public byte HWResetFunction;
|
|
|
|
|
public byte InitializationTimeAfterPartition;
|
|
|
|
|
public byte InitializationTimeout;
|
|
|
|
|
public byte LargeUnitSize;
|
|
|
|
|
public byte ManuallyStartBackgroundOperations;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
|
|
|
public byte[] MaxEnhancedAreaSize;
|
|
|
|
|
public byte MaxPackedReadCommands;
|
|
|
|
|
public byte MaxPackedWriteCommands;
|
|
|
|
|
public uint MaxPreLoadingDataSize;
|
|
|
|
|
public byte MinimumReadPerformance26;
|
|
|
|
|
public byte MinimumReadPerformance26_4;
|
|
|
|
|
public byte MinimumReadPerformance52;
|
|
|
|
|
public byte MinimumReadPerformanceDDR52;
|
|
|
|
|
public byte MinimumWritePerformance26;
|
|
|
|
|
public byte MinimumWritePerformance26_4;
|
|
|
|
|
public byte MinimumWritePerformance52;
|
|
|
|
|
public byte MinimumWritePerformanceDDR52;
|
|
|
|
|
public byte ModeConfig;
|
|
|
|
|
public byte ModeOperationCodes;
|
|
|
|
|
public byte NativeSectorSize;
|
|
|
|
|
public uint NumberofFWSectorsCorrectlyProgrammed;
|
|
|
|
|
public byte OperationCodesTimeout;
|
|
|
|
|
public byte OptimalReadSize;
|
|
|
|
|
public byte OptimalTrimUnitSize;
|
|
|
|
|
public byte OptimalWriteSize;
|
|
|
|
|
public byte OutOfInterruptBusyTiming;
|
|
|
|
|
public byte PackageCaseTemperatureControl;
|
|
|
|
|
public byte PackedCommandFailureIndex;
|
|
|
|
|
public byte PackedCommandStatus;
|
|
|
|
|
public byte PartitionConfiguration;
|
|
|
|
|
public byte PartitioningSetting;
|
|
|
|
|
public byte PartitioningSupport;
|
|
|
|
|
public byte PartitionsAttribute;
|
|
|
|
|
public byte PartitionSwitchingTime;
|
|
|
|
|
public byte PeriodicWakeUp;
|
|
|
|
|
public byte PowerClass;
|
|
|
|
|
public byte PowerClass26;
|
|
|
|
|
public byte PowerClass26_195;
|
|
|
|
|
public byte PowerClass52;
|
|
|
|
|
public byte PowerClass52_195;
|
|
|
|
|
public byte PowerClassDDR200;
|
|
|
|
|
public byte PowerClassDDR200_130;
|
|
|
|
|
public byte PowerClassDDR200_195;
|
|
|
|
|
public byte PowerClassDDR52;
|
|
|
|
|
public byte PowerClassDDR52_195;
|
|
|
|
|
public byte PowerOffNotification;
|
|
|
|
|
public byte PowerOffNotificationTimeout;
|
|
|
|
|
public byte PreEOLInformation;
|
|
|
|
|
public uint PreLoadingDataSize;
|
|
|
|
|
public byte ProductionStateAwareness;
|
|
|
|
|
public byte ProductionStateAwarenessTimeout;
|
|
|
|
|
public byte ProductStateAwarenessEnablement;
|
|
|
|
|
public byte ReliableWriteSectorCount;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
|
|
|
public byte[] Reserved0;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)]
|
|
|
|
|
public byte[] Reserved1;
|
|
|
|
|
public byte Reserved10;
|
|
|
|
|
public byte Reserved11;
|
|
|
|
|
public byte Reserved12;
|
|
|
|
|
public byte Reserved13;
|
|
|
|
|
public byte Reserved14;
|
|
|
|
|
public byte Reserved15;
|
|
|
|
|
public ushort Reserved16;
|
|
|
|
|
public ushort Reserved17;
|
2018-06-22 08:08:38 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
|
|
|
|
public byte[] Reserved18;
|
2019-11-25 00:54:38 +00:00
|
|
|
public byte Reserved2;
|
|
|
|
|
public byte Reserved3;
|
|
|
|
|
public byte Reserved4;
|
|
|
|
|
public byte Reserved5;
|
|
|
|
|
public byte Reserved6;
|
|
|
|
|
public byte Reserved7;
|
|
|
|
|
public byte Reserved8;
|
|
|
|
|
public byte Reserved9;
|
|
|
|
|
public byte Revision;
|
|
|
|
|
public byte RPMBSize;
|
|
|
|
|
public uint SectorCount;
|
|
|
|
|
public byte SectorSize;
|
|
|
|
|
public byte SectorSizeEmulation;
|
|
|
|
|
public byte SecureEraseMultiplier;
|
|
|
|
|
public byte SecureFeatureSupport;
|
|
|
|
|
public byte SecureRemovalType;
|
|
|
|
|
public byte SecureTRIMMultiplier;
|
|
|
|
|
public byte SecureWriteProtectInformation;
|
|
|
|
|
public byte SleepAwakeTimeout;
|
|
|
|
|
public byte SleepCurrentVcc;
|
|
|
|
|
public byte SleepCurrentVccq;
|
|
|
|
|
public byte SleepNotificationTimeout;
|
|
|
|
|
public byte StartSanitizeOperation;
|
|
|
|
|
public byte StrobeSupport;
|
|
|
|
|
public byte Structure;
|
|
|
|
|
public byte SupportedCommandSets;
|
|
|
|
|
public byte SupportedModes;
|
|
|
|
|
public byte SupportsProgramCxDInDDR;
|
|
|
|
|
public byte TagResourcesSize;
|
|
|
|
|
public byte TagUnitSize;
|
|
|
|
|
public byte TRIMMultiplier;
|
|
|
|
|
public byte UserAreaWriteProtectionRegister;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
|
|
|
|
public byte[] VendorHealthReport;
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
|
|
|
|
|
public byte[] VendorSpecific;
|
|
|
|
|
public byte WriteReliabilityParameterRegister;
|
|
|
|
|
public byte WriteReliabilitySettingRegister;
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
|
|
|
|
|
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
2017-12-22 02:04:18 +00:00
|
|
|
public static partial class Decoders
|
2016-10-22 22:58:01 +01:00
|
|
|
{
|
|
|
|
|
public static ExtendedCSD DecodeExtendedCSD(byte[] response)
|
|
|
|
|
{
|
2019-11-25 00:54:38 +00:00
|
|
|
if(response == null)
|
|
|
|
|
return null;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if(response.Length != 512)
|
|
|
|
|
return null;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
GCHandle handle = GCHandle.Alloc(response, GCHandleType.Pinned);
|
|
|
|
|
var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));
|
2016-10-22 22:58:01 +01:00
|
|
|
handle.Free();
|
|
|
|
|
|
|
|
|
|
return csd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string PrettifyExtendedCSD(ExtendedCSD csd)
|
|
|
|
|
{
|
2019-11-25 00:54:38 +00:00
|
|
|
if(csd == null)
|
|
|
|
|
return null;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
var sb = new StringBuilder();
|
2016-10-22 22:58:01 +01:00
|
|
|
sb.AppendLine("MultiMediaCard Extended Device Specific Data Register:");
|
|
|
|
|
|
|
|
|
|
double unit;
|
|
|
|
|
|
|
|
|
|
if((csd.HPIFeatures & 0x01) == 0x01)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendLine((csd.HPIFeatures & 0x02) == 0x02 ? "\tDevice implements HPI using CMD12"
|
2018-06-20 22:22:21 +01:00
|
|
|
: "\tDevice implements HPI using CMD13");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if((csd.BackgroundOperationsSupport & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports background operations");
|
|
|
|
|
|
2017-12-19 20:33:03 +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
|
|
|
|
|
|
|
|
if((csd.DataTagSupport & 0x01) == 0x01)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports Data Tag");
|
|
|
|
|
sb.AppendFormat("\tTags must be in units of {0} sectors", Math.Pow(2, csd.TagUnitSize)).AppendLine();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((csd.ExtendedPartitionsSupport & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports non-persistent extended partitions");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if((csd.ExtendedPartitionsSupport & 0x02) == 0x02)
|
|
|
|
|
sb.AppendLine("\tDevice supports system code extended partitions");
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.SupportedModes & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports FFU");
|
|
|
|
|
|
|
|
|
|
if((csd.SupportedModes & 0x02) == 0x02)
|
|
|
|
|
sb.AppendLine("\tDevice supports Vendor Specific Mode");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if((csd.CMDQueuingSupport & 0x01) == 0x01)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice supports command queuing with a depth of {0}", csd.CMDQueuingDepth + 1).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberofFWSectorsCorrectlyProgrammed).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(csd.PreEOLInformation)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice informs it's in good health");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice informs it should be replaced soon");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice informs it should be replace immediately");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb.AppendFormat("\tOptimal read size is {0} logical sectors", csd.OptimalReadSize).AppendLine();
|
|
|
|
|
sb.AppendFormat("\tOptimal write size is {0} logical sectors", csd.OptimalWriteSize).AppendLine();
|
|
|
|
|
sb.AppendFormat("\tOptimal trim size is {0} logical sectors", csd.OptimalTrimUnitSize).AppendLine();
|
|
|
|
|
|
|
|
|
|
sb.AppendFormat("\tDevice version: {0}", csd.DeviceVersion).AppendLine();
|
|
|
|
|
sb.AppendFormat("\tFirmware version: {0}", csd.FirmwareVersion).AppendLine();
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if(csd.CacheSize == 0)
|
|
|
|
|
sb.AppendLine("\tDevice has no cache");
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.GenericCMD6Timeout > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms by default for a SWITCH command",
|
|
|
|
|
csd.GenericCMD6Timeout * 10).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.PowerOffNotificationTimeout > 0)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.
|
|
|
|
|
AppendFormat("\tDevice takes a maximum of {0} by default to power off from a SWITCH command notification",
|
2018-06-22 08:08:38 +01:00
|
|
|
csd.PowerOffNotificationTimeout * 10).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
switch(csd.BackgroundOperationsStatus & 0x03)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice has no pending background operations");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice has non critical operations outstanding");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice has performance impacted operations outstanding");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tDevice has critical operations outstanding");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tLast WRITE MULTIPLE command correctly programmed {0} sectors",
|
|
|
|
|
csd.CorrectlyProgrammedSectors).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.InitializationTimeAfterPartition > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
if((csd.CacheFlushingPolicy & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice uses a FIFO policy for cache flushing");
|
|
|
|
|
|
|
|
|
|
if(csd.TRIMMultiplier > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group",
|
|
|
|
|
csd.TRIMMultiplier * 300).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.SecureFeatureSupport & 0x40) == 0x40)
|
|
|
|
|
sb.AppendLine("\tDevice supports the sanitize operation");
|
|
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if((csd.SecureFeatureSupport & 0x10) == 0x10)
|
|
|
|
|
sb.AppendLine("\tDevice supports supports the secure and insecure trim operations");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if((csd.SecureFeatureSupport & 0x04) == 0x04)
|
|
|
|
|
sb.AppendLine("\tDevice supports automatic erase on retired defective blocks");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
|
|
|
|
if((csd.SecureFeatureSupport & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports secure purge operations");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.SecureEraseMultiplier > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
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
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.SecureTRIMMultiplier > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely trimming a single erase group",
|
|
|
|
|
csd.SecureTRIMMultiplier * 300).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.BootInformation & 0x04) == 0x04)
|
|
|
|
|
sb.AppendLine("\tDevice supports high speed timing on boot");
|
|
|
|
|
|
|
|
|
|
if((csd.BootInformation & 0x02) == 0x02)
|
|
|
|
|
sb.AppendLine("\tDevice supports dual data rate on boot");
|
|
|
|
|
|
|
|
|
|
if((csd.BootInformation & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports alternative boot method");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.BootPartitionSize > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice has a {0} KiB boot partition", csd.BootPartitionSize * 128).AppendLine();
|
|
|
|
|
|
|
|
|
|
if((csd.AccessSize & 0x0F) > 0)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice has a page size of {0} KiB", (csd.AccessSize & 0x0F) * 512.0 / 1024.0).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.HighCapacityEraseUnitSize > 0)
|
|
|
|
|
sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine();
|
|
|
|
|
|
|
|
|
|
if(csd.HighCapacityEraseTimeout > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms for erasing a single erase group",
|
|
|
|
|
csd.HighCapacityEraseTimeout * 300).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.HighCapacityWriteProtectGroupSize > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice smallest write protect group is made of {0} erase groups",
|
|
|
|
|
csd.HighCapacityWriteProtectGroupSize).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.SleepCurrentVcc > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepCurrentVcc);
|
2019-11-25 00:54:38 +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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(csd.SleepCurrentVccq > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepCurrentVccq);
|
2019-11-25 00:54:38 +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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(csd.ProductionStateAwarenessTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.ProductionStateAwareness) * 100;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(unit > 1000000)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} s to switch production state awareness",
|
|
|
|
|
unit / 1000000).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
else if(unit > 1000)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to switch production state awareness",
|
|
|
|
|
unit / 1000).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to switch production state awareness", unit).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(csd.SleepAwakeTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepAwakeTimeout) * 100;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(unit > 1000000)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to transition between sleep and standby states",
|
|
|
|
|
unit / 1000000).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
else if(unit > 1000)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to transition between sleep and standby states",
|
|
|
|
|
unit / 1000).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
else
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ns to transition between sleep and standby states",
|
|
|
|
|
unit).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(csd.SleepNotificationTimeout > 0)
|
|
|
|
|
{
|
|
|
|
|
unit = Math.Pow(2, csd.SleepNotificationTimeout) * 10;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(unit > 1000000)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} s to move to sleep state", unit / 1000000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
else if(unit > 1000)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} ms to move to sleep state", unit / 1000).
|
|
|
|
|
AppendLine();
|
|
|
|
|
else
|
|
|
|
|
sb.AppendFormat("\tDevice takes a maximum of {0} μs to move to sleep state", unit).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb.AppendFormat("\tDevice has {0} sectors", csd.SectorCount).AppendLine();
|
|
|
|
|
|
|
|
|
|
if((csd.SecureWriteProtectInformation & 0x01) == 0x01)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports secure write protection");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if((csd.SecureWriteProtectInformation & 0x02) == 0x02)
|
|
|
|
|
sb.AppendLine("\tDevice has secure write protection enabled");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit = csd.MinimumReadPerformance26 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumReadPerformance26 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumReadPerformance26_4 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumReadPerformance26_4 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode");
|
|
|
|
|
else
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode",
|
|
|
|
|
unit / 1000).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumReadPerformance52 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumReadPerformance52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 52Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumReadPerformanceDDR52 * 300;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumReadPerformanceDDR52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 4.8MB/s reading in DDR 52Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumWritePerformance26 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumWritePerformance26 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumWritePerformance26_4 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumWritePerformance26_4 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode");
|
|
|
|
|
else
|
2017-12-19 20:33:03 +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
|
|
|
|
|
|
|
|
unit = csd.MinimumWritePerformance52 * 150;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumWritePerformance52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 52Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
unit = csd.MinimumWritePerformanceDDR52 * 300;
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(csd.MinimumWritePerformanceDDR52 == 0)
|
|
|
|
|
sb.AppendLine("\tDevice cannot achieve 4.8MB/s writing in DDR 52Mhz mode");
|
|
|
|
|
else
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode", unit / 1000).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.PartitionSwitchingTime > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice can take a maximum of {0} ms when switching partitions",
|
|
|
|
|
csd.PartitionSwitchingTime * 10).AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.OutOfInterruptBusyTiming > 0)
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt",
|
|
|
|
|
csd.OutOfInterruptBusyTiming * 10).AppendLine();
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.DeviceType & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice supports 26 Mhz mode");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x02) == 0x02)
|
|
|
|
|
sb.AppendLine("\tDevice supports 52 Mhz mode");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x04) == 0x04)
|
|
|
|
|
sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x08) == 0x08)
|
|
|
|
|
sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x10) == 0x10)
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x20) == 0x20)
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x40) == 0x40)
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V");
|
|
|
|
|
|
|
|
|
|
if((csd.DeviceType & 0x80) == 0x80)
|
|
|
|
|
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.2V");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
sb.AppendFormat("\tCSD version 1.{0} revision 1.{1}", csd.Structure, csd.Revision).AppendLine();
|
|
|
|
|
|
|
|
|
|
if((csd.StrobeSupport & 0x01) == 0x01)
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine("\tDevice supports enhanced strobe mode");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2018-06-20 22:22:21 +01:00
|
|
|
sb.AppendLine((csd.BusWidth & 0x80) == 0x80
|
|
|
|
|
? "\tDevice uses strobe during Data Out, CRC and CMD responses"
|
|
|
|
|
: "\tDevice uses strobe during Data Out and CRC responses");
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(csd.BusWidth & 0x0F)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is using 1-bit data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice is using 4-bit data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice is using 8-bit data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
sb.AppendLine("\tDevice is using 4-bit DDR data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
sb.AppendLine("\tDevice is using 8-bit DDR data bus");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01: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
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.PartitionConfiguration & 0x80) == 0x80)
|
|
|
|
|
sb.AppendLine("\tDevice sends boot acknowledge");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
switch((csd.PartitionConfiguration & 0x38) >> 3)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is not boot enabled");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice boot partition 1 is enabled");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tDevice boot partition 2 is enabled");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
sb.AppendLine("\tDevice user area is enable for boot");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tUnknown enabled boot partition code {0}",
|
|
|
|
|
(csd.PartitionConfiguration & 0x38) >> 3).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(csd.PartitionConfiguration & 0x07)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tThere is no access to boot partition");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to boot partition 1");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to boot partition 2");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
sb.AppendLine("\tThere is read/write access to replay protected memory block");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tThere is access to general purpose partition {0}",
|
|
|
|
|
(csd.PartitionConfiguration & 0x07) - 3).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.FirmwareConfiguration & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tFirmware updates are permanently disabled");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
if(csd.RPMBSize > 0)
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice has a {0} KiB replay protected memory block", csd.RPMBSize * 128).
|
|
|
|
|
AppendLine();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
switch(csd.NativeSectorSize)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice natively uses 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice natively uses 4096 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice natively uses unknown sector size indicated by code {0}",
|
|
|
|
|
csd.NativeSectorSize).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(csd.SectorSizeEmulation)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice is emulating 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice is using natively sized sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2019-11-25 00:54:38 +00:00
|
|
|
sb.AppendFormat("\tDevice emulates unknown sector size indicated by code {0}",
|
|
|
|
|
csd.NativeSectorSize).AppendLine();
|
|
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(csd.SectorSize)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sb.AppendLine("\tDevice currently addresses 512 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sb.AppendLine("\tDevice currently addresses 4096 byte sectors");
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-12-19 20:33:03 +00:00
|
|
|
sb.AppendFormat("\tDevice currently addresses unknown sector size indicated by code {0}",
|
|
|
|
|
csd.NativeSectorSize).AppendLine();
|
2019-11-25 00:54:38 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.CacheControl & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice's cache is enabled");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2019-11-25 00:54:38 +00:00
|
|
|
if((csd.CommandQueueModeEnable & 0x01) == 0x01)
|
|
|
|
|
sb.AppendLine("\tDevice has enabled command queuing");
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-31 13:17:27 +00:00
|
|
|
public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response));
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|