mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 11:14:25 +00:00
1426 lines
54 KiB
C#
1426 lines
54 KiB
C#
// /***************************************************************************
|
|
// Aaru Data Preservation Suite
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : ExtendedCSD.cs
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// Component : Device structures decoders.
|
|
//
|
|
// --[ Description ] ----------------------------------------------------------
|
|
//
|
|
// Decodes MultiMediaCard extended CSD.
|
|
//
|
|
// --[ 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/>.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright © 2011-2023 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Aaru.Decoders.MMC;
|
|
|
|
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
|
[SuppressMessage("ReSharper", "UnassignedField.Global")]
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
|
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
|
public class ExtendedCSD
|
|
{
|
|
public byte AccessSize;
|
|
public byte BackgroundOperationsStatus;
|
|
public BackgroundOperationsSupport BackgroundOperationsSupport;
|
|
public byte BadBlockManagementMode;
|
|
public byte BarrierControl;
|
|
public byte BarrierSupport;
|
|
public BootAreaWriteProtectionRegister BootAreaWriteProtectionRegister;
|
|
public byte BootBusConditions;
|
|
public BootConfigProtection BootConfigProtection;
|
|
public BootInformation BootInformation;
|
|
public byte BootPartitionSize;
|
|
public byte BootWriteProtectionStatus;
|
|
public byte BusWidth;
|
|
public byte CacheControl;
|
|
public byte CacheFlushing;
|
|
public CacheFlushingPolicy CacheFlushingPolicy;
|
|
public uint CacheSize;
|
|
public byte Class6CommandsControl;
|
|
public byte CMDQueuingDepth;
|
|
public CMDQueuingSupport 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 DataTagSupport DataTagSupport;
|
|
public byte DeviceLifeEstimationTypeA;
|
|
public byte DeviceLifeEstimationTypeB;
|
|
public DeviceType DeviceType;
|
|
public ushort DeviceVersion;
|
|
public DriverStrength DriverStrength;
|
|
public byte DyncapNeeded;
|
|
public byte EnableBackgroundOperationsHandshake;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
public byte[] EnhancedUserDataAreaSize;
|
|
public uint EnhancedUserDataStartAddress;
|
|
public byte ErasedMemoryContent;
|
|
public ushort ExceptionEventsControl;
|
|
public ushort ExceptionEventsStatus;
|
|
public ushort ExtendedPartitionsAttribute;
|
|
public ExtendedPartitionsSupport ExtendedPartitionsSupport;
|
|
public byte ExtendedSecurityCommandsError;
|
|
public uint FFUArgument;
|
|
public FFUFeatures FFUFeatures;
|
|
public byte FFUStatus;
|
|
public byte FirmwareConfiguration;
|
|
public ulong FirmwareVersion;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
|
|
public byte[] GeneralPurposePartitionSize;
|
|
public byte GenericCMD6Timeout;
|
|
public HighCapacityEraseGroupDefinition HighCapacityEraseGroupDefinition;
|
|
public byte HighCapacityEraseTimeout;
|
|
public byte HighCapacityEraseUnitSize;
|
|
public byte HighCapacityWriteProtectGroupSize;
|
|
public byte HighSpeedInterfaceTiming;
|
|
public HPIFeatures HPIFeatures;
|
|
public byte HPIManagement;
|
|
public byte HWResetFunction;
|
|
public byte InitializationTimeAfterPartition;
|
|
public byte InitializationTimeoutAfterEmulationChange;
|
|
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 PartitioningSupport 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 = 15)]
|
|
public byte[] Reserved0;
|
|
public ushort Reserved1;
|
|
public byte Reserved10;
|
|
public byte Reserved11;
|
|
public byte Reserved12;
|
|
public byte Reserved13;
|
|
public byte Reserved14;
|
|
public byte Reserved15;
|
|
public byte Reserved16;
|
|
public byte Reserved17;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)]
|
|
public byte[] Reserved18;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
public byte[] Reserved19;
|
|
public ushort 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 SecureFeatureSupport SecureFeatureSupport;
|
|
public byte SecureRemovalType;
|
|
public byte SecureTRIMMultiplier;
|
|
public SecureWriteProtectInformation SecureWriteProtectInformation;
|
|
public byte SleepAwakeTimeout;
|
|
public byte SleepCurrentVcc;
|
|
public byte SleepCurrentVccQ;
|
|
public byte SleepNotificationTimeout;
|
|
public byte StartSanitizeOperation;
|
|
public byte StrobeSupport;
|
|
public byte Structure;
|
|
public DeviceSupportedCommandSets SupportedCommandSets;
|
|
public SupportedModes SupportedModes;
|
|
public byte SupportsProgramCxDInDDR;
|
|
public byte TagResourcesSize;
|
|
public byte TagUnitSize;
|
|
public byte TRIMMultiplier;
|
|
public UserAreaWriteProtectionRegister UserAreaWriteProtectionRegister;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
|
public byte[] VendorHealthReport;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
|
|
public byte[] VendorSpecific;
|
|
public byte WriteReliabilityParameterRegister;
|
|
public byte WriteReliabilitySettingRegister;
|
|
}
|
|
|
|
[Flags]
|
|
public enum DeviceSupportedCommandSets : byte
|
|
{
|
|
Standard = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum HPIFeatures : byte
|
|
{
|
|
Supported = 1 << 0,
|
|
CMD12 = 1 << 1
|
|
}
|
|
|
|
[Flags]
|
|
public enum BackgroundOperationsSupport : byte
|
|
{
|
|
Supported = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum DataTagSupport : byte
|
|
{
|
|
Supported = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum ExtendedPartitionsSupport : byte
|
|
{
|
|
SystemCode = 1 << 0,
|
|
NonPersistent = 1 << 1
|
|
}
|
|
|
|
[Flags]
|
|
public enum SupportedModes : byte
|
|
{
|
|
FFU = 1 << 0,
|
|
VendorSpecific = 1 << 1
|
|
}
|
|
|
|
[Flags]
|
|
public enum FFUFeatures : byte
|
|
{
|
|
SupportedModeOperationCodes = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum CMDQueuingSupport : byte
|
|
{
|
|
Supported = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum CacheFlushingPolicy : byte
|
|
{
|
|
FIFO = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum SecureFeatureSupport : byte
|
|
{
|
|
Purge = 1 << 0,
|
|
Defective = 1 << 2,
|
|
Trim = 1 << 4,
|
|
Sanitize = 1 << 6
|
|
}
|
|
|
|
[Flags]
|
|
public enum BootInformation : byte
|
|
{
|
|
Alternative = 1 << 0,
|
|
DDR = 1 << 1,
|
|
HighSpeed = 1 << 2
|
|
}
|
|
|
|
[Flags]
|
|
public enum SecureWriteProtectInformation : byte
|
|
{
|
|
Supported = 1 << 0,
|
|
Enabled = 1 << 1
|
|
}
|
|
|
|
[Flags]
|
|
public enum DriverStrength : byte
|
|
{
|
|
Type0 = 1 << 0,
|
|
Type1 = 1 << 1,
|
|
Type2 = 1 << 2,
|
|
Type3 = 1 << 3,
|
|
Type4 = 1 << 4
|
|
}
|
|
|
|
[Flags]
|
|
public enum DeviceType : byte
|
|
{
|
|
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
|
|
}
|
|
|
|
[Flags]
|
|
public enum BootConfigProtection : byte
|
|
{
|
|
PowerCycle = 1 << 0,
|
|
Permanent = 1 << 4
|
|
}
|
|
|
|
[Flags]
|
|
public enum HighCapacityEraseGroupDefinition : byte
|
|
{
|
|
Enabled = 1 << 0
|
|
}
|
|
|
|
[Flags]
|
|
public enum BootAreaWriteProtectionRegister : byte
|
|
{
|
|
PowerOn = 1 << 0,
|
|
PowerOnArea2 = 1 << 1,
|
|
Permanent = 1 << 2,
|
|
PermanentArea2 = 1 << 3,
|
|
PermanentDisable = 1 << 4,
|
|
PowerOnDisable = 1 << 6,
|
|
Selected = 1 << 7
|
|
}
|
|
|
|
[Flags]
|
|
public enum UserAreaWriteProtectionRegister : byte
|
|
{
|
|
ApplyPowerOn = 1 << 0,
|
|
ApplyPermanent = 1 << 2,
|
|
DisablePowerOn = 1 << 3,
|
|
DisablePermanent = 1 << 4,
|
|
DisableWriteProtect = 1 << 6,
|
|
DisablePassword = 1 << 7
|
|
}
|
|
|
|
[Flags]
|
|
public enum PartitioningSupport : byte
|
|
{
|
|
Supported = 1 << 0,
|
|
Enhanced = 1 << 1,
|
|
Extended = 1 << 2
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
|
public static partial class Decoders
|
|
{
|
|
public static ExtendedCSD DecodeExtendedCSD(byte[] response)
|
|
{
|
|
if(response?.Length != 512)
|
|
return null;
|
|
|
|
var handle = GCHandle.Alloc(response, GCHandleType.Pinned);
|
|
var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));
|
|
handle.Free();
|
|
|
|
return csd;
|
|
}
|
|
|
|
public static string PrettifyExtendedCSD(ExtendedCSD csd)
|
|
{
|
|
if(csd == null)
|
|
return null;
|
|
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine(Localization.MultiMediaCard_Extended_Device_Specific_Data_Register);
|
|
|
|
double unit;
|
|
|
|
if(csd.ExtendedSecurityCommandsError != 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Last_extended_security_error_was_0, csd.ExtendedSecurityCommandsError).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard))
|
|
sb.AppendLine("\t" + Localization.Device_supports_standard_MMC_command_set);
|
|
|
|
if(((int)csd.SupportedCommandSets & 0xFE) != 0)
|
|
sb.AppendFormat("\t" + Localization.Device_supports_unknown_command_sets_0, (int)csd.SupportedCommandSets);
|
|
|
|
if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported))
|
|
{
|
|
sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12)
|
|
? "\t" + Localization.Device_implements_HPI_using_CMD12
|
|
: "\t" + Localization.Device_implements_HPI_using_CMD13);
|
|
}
|
|
|
|
if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported))
|
|
sb.AppendLine("\t" + Localization.Device_supports_background_operations);
|
|
|
|
sb.AppendFormat("\t" + Localization.Device_supports_a_maximum_of_0_packed_reads_and_1_packed_writes,
|
|
csd.MaxPackedReadCommands, csd.MaxPackedWriteCommands).
|
|
AppendLine();
|
|
|
|
if(csd.DataTagSupport.HasFlag(DataTagSupport.Supported))
|
|
{
|
|
sb.AppendLine("\t" + Localization.Device_supports_Data_Tag);
|
|
|
|
sb.AppendFormat("\t" + Localization.Tags_must_be_in_units_of_0_sectors, Math.Pow(2, csd.TagUnitSize)).
|
|
AppendLine();
|
|
|
|
sb.AppendFormat("\t" + Localization.Tag_resources_size_is_0, csd.TagResourcesSize).AppendLine();
|
|
}
|
|
|
|
if(csd.ContextManagementCaps != 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Max_context_ID_is_0, csd.ContextManagementCaps & 0xF).AppendLine();
|
|
|
|
sb.AppendFormat("\t" + Localization.Large_unit_maximum_multiplier_is_0,
|
|
((csd.ContextManagementCaps & 0x70) >> 4) + 1).
|
|
AppendLine();
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization.Large_unit_size_is_0_MiB, csd.LargeUnitSize + 1).AppendLine();
|
|
|
|
if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent))
|
|
sb.AppendLine("\t" + Localization.Device_supports_non_persistent_extended_partitions);
|
|
|
|
if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode))
|
|
sb.AppendLine("\t" + Localization.Device_supports_system_code_extended_partitions);
|
|
|
|
if(csd.SupportedModes.HasFlag(SupportedModes.FFU))
|
|
{
|
|
sb.AppendLine("\t" + Localization.Device_supports_FFU);
|
|
|
|
if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes))
|
|
|
|
// todo public byte ModeOperationCodes
|
|
|
|
{
|
|
if(csd.OperationCodesTimeout > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.OperationCodesTimeout) * 100;
|
|
|
|
switch(unit)
|
|
{
|
|
case > 1000000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_s,
|
|
unit / 1000000).
|
|
AppendLine();
|
|
|
|
break;
|
|
case > 1000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_ms,
|
|
unit / 1000).
|
|
AppendLine();
|
|
|
|
break;
|
|
default:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Maximum_timeout_for_switch_command_when_setting_a_value_to_the_mode_operation_codes_field_is_0_µs,
|
|
unit).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific))
|
|
sb.AppendLine("\t" + Localization.Device_supports_Vendor_Specific_Mode);
|
|
|
|
if(csd.BarrierSupport == 0x01)
|
|
sb.AppendLine("\t" + Localization.Device_supports_the_barrier_command);
|
|
|
|
if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported))
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_supports_command_queuing_with_a_depth_of_0,
|
|
csd.CMDQueuingDepth + 1).
|
|
AppendLine();
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization._0_firmware_sectors_correctly_programmed,
|
|
csd.NumberOfFWSectorsCorrectlyProgrammed).
|
|
AppendLine();
|
|
|
|
switch(csd.DeviceLifeEstimationTypeB)
|
|
{
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_zero_and_10_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_10_and_20_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_20_and_30_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 4:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_30_and_40_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 5:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_40_and_50_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 6:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_50_and_60_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 7:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_60_and_70_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 8:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_70_and_80_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 9:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_80_and_90_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 10:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_90_and_100_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 11:
|
|
sb.AppendLine("\t" + Localization.Device_exceeded_its_maximum_estimated_life_time);
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.DeviceLifeEstimationTypeA)
|
|
{
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_zero_and_10_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_10_and_20_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_20_and_30_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 4:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_30_and_40_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 5:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_40_and_50_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 6:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_50_and_60_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 7:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_60_and_70_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 8:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_70_and_80_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 9:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_80_and_90_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 10:
|
|
sb.AppendLine("\t" + Localization.Device_used_between_90_and_100_of_its_estimated_life_time);
|
|
|
|
break;
|
|
case 11:
|
|
sb.AppendLine("\t" + Localization.Device_exceeded_its_maximum_estimated_life_time);
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.PreEOLInformation)
|
|
{
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_informs_its_in_good_health);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_informs_it_should_be_replaced_soon);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_informs_it_should_be_replace_immediately);
|
|
|
|
break;
|
|
}
|
|
|
|
if(csd.OptimalReadSize == 0)
|
|
sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_read_size);
|
|
else
|
|
sb.AppendFormat("\t" + Localization.Optimal_read_size_is_0_KiB, 4 * csd.OptimalReadSize).AppendLine();
|
|
|
|
if(csd.OptimalWriteSize == 0)
|
|
sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_write_size);
|
|
else
|
|
sb.AppendFormat("\t" + Localization.Optimal_write_size_is_0_KiB, 4 * csd.OptimalWriteSize).AppendLine();
|
|
|
|
if(csd.OptimalTrimUnitSize == 0)
|
|
sb.AppendLine("\t" + Localization.Device_does_not_report_an_optimal_trim_size);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Optimal_trim_size_is_0_KiB,
|
|
4 * Math.Pow(2, csd.OptimalTrimUnitSize - 1)).
|
|
AppendLine();
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization.Device_version_0, csd.DeviceVersion).AppendLine();
|
|
sb.AppendFormat("\t" + Localization.Firmware_version_0, csd.FirmwareVersion).AppendLine();
|
|
|
|
if(csd.CacheSize == 0)
|
|
sb.AppendLine("\t" + Localization.Device_has_no_cache);
|
|
else
|
|
sb.AppendFormat("\t" + Localization.Device_has_0_KiB_of_cache, csd.CacheSize / 8).AppendLine();
|
|
|
|
if(csd.GenericCMD6Timeout > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_by_default_for_a_SWITCH_command,
|
|
csd.GenericCMD6Timeout * 10).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.PowerOffNotificationTimeout > 0)
|
|
{
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_by_default_to_power_off_from_a_SWITCH_command_notification,
|
|
csd.PowerOffNotificationTimeout * 10).
|
|
AppendLine();
|
|
}
|
|
|
|
switch(csd.BackgroundOperationsStatus & 0x03)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_has_no_pending_background_operations);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_has_non_critical_operations_outstanding);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_has_performance_impacted_operations_outstanding);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_has_critical_operations_outstanding);
|
|
|
|
break;
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization.Last_WRITE_MULTIPLE_command_correctly_programmed_0_sectors,
|
|
csd.CorrectlyProgrammedSectors).
|
|
AppendLine();
|
|
|
|
if(csd.InitializationTimeAfterPartition > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_initialization_after_partition,
|
|
csd.InitializationTimeAfterPartition * 100).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO))
|
|
sb.AppendLine("\t" + Localization.Device_uses_a_FIFO_policy_for_cache_flushing);
|
|
|
|
if(csd.TRIMMultiplier > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_trimming_a_single_erase_group,
|
|
csd.TRIMMultiplier * 300).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize))
|
|
sb.AppendLine("\t" + Localization.Device_supports_the_sanitize_operation);
|
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim))
|
|
sb.AppendLine("\t" + Localization.Device_supports_supports_the_secure_and_insecure_trim_operations);
|
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective))
|
|
sb.AppendLine("\t" + Localization.Device_supports_automatic_erase_on_retired_defective_blocks);
|
|
|
|
if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge))
|
|
sb.AppendLine("\t" + Localization.Device_supports_secure_purge_operations);
|
|
|
|
if(csd.SecureEraseMultiplier > 0)
|
|
{
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_securely_erasing_a_single_erase_group,
|
|
csd.SecureEraseMultiplier * 300).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.SecureTRIMMultiplier > 0)
|
|
{
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_securely_trimming_a_single_erase_group,
|
|
csd.SecureTRIMMultiplier * 300).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.HighSpeed))
|
|
sb.AppendLine("\t" + Localization.Device_supports_high_speed_timing_on_boot);
|
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.DDR))
|
|
sb.AppendLine("\t" + Localization.Device_supports_dual_data_rate_on_boot);
|
|
|
|
if(csd.BootInformation.HasFlag(BootInformation.Alternative))
|
|
sb.AppendLine("\t" + Localization.Device_supports_alternative_boot_method);
|
|
|
|
if(csd.BootPartitionSize > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_has_a_0_KiB_boot_partition, csd.BootPartitionSize * 128).
|
|
AppendLine();
|
|
}
|
|
|
|
if((csd.AccessSize & 0x0F) > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_has_a_page_size_of_0_KiB,
|
|
512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.HighCapacityEraseUnitSize > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_erase_groups_are_0_KiB, csd.HighCapacityEraseUnitSize * 512).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.HighCapacityEraseTimeout > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_for_erasing_a_single_erase_group,
|
|
csd.HighCapacityEraseTimeout * 300).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.HighCapacityWriteProtectGroupSize > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_smallest_write_protect_group_is_made_of_0_erase_groups,
|
|
csd.HighCapacityWriteProtectGroupSize).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.SleepCurrentVcc > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.SleepCurrentVcc);
|
|
|
|
if(unit > 1000)
|
|
sb.AppendFormat("\t" + Localization.Device_uses_0_mA_on_Vcc_when_sleeping, unit / 1000).AppendLine();
|
|
else
|
|
sb.AppendFormat("\t" + Localization.Device_uses_0_μA_on_Vcc_when_sleeping, unit).AppendLine();
|
|
}
|
|
|
|
if(csd.SleepCurrentVccQ > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.SleepCurrentVccQ);
|
|
|
|
if(unit > 1000)
|
|
sb.AppendFormat("\t" + Localization.Device_uses_0_mA_on_Vccq_when_sleeping, unit / 1000).AppendLine();
|
|
else
|
|
sb.AppendFormat("\t" + Localization.Device_uses_0_μA_on_Vccq_when_sleeping, unit).AppendLine();
|
|
}
|
|
|
|
if(csd.ProductionStateAwarenessTimeout > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.ProductionStateAwareness) * 100;
|
|
|
|
switch(unit)
|
|
{
|
|
case > 1000000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_s_to_switch_production_state_awareness,
|
|
unit / 1000000).
|
|
AppendLine();
|
|
|
|
break;
|
|
case > 1000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_to_switch_production_state_awareness,
|
|
unit / 1000).
|
|
AppendLine();
|
|
|
|
break;
|
|
default:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_μs_to_switch_production_state_awareness,
|
|
unit).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(csd.SleepAwakeTimeout > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.SleepAwakeTimeout) * 100;
|
|
|
|
switch(unit)
|
|
{
|
|
case > 1000000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_to_transition_between_sleep_and_standby_states,
|
|
unit / 1000000).
|
|
AppendLine();
|
|
|
|
break;
|
|
case > 1000:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_μs_to_transition_between_sleep_and_standby_states,
|
|
unit / 1000).
|
|
AppendLine();
|
|
|
|
break;
|
|
default:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ns_to_transition_between_sleep_and_standby_states,
|
|
unit).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(csd.SleepNotificationTimeout > 0)
|
|
{
|
|
unit = Math.Pow(2, csd.SleepNotificationTimeout) * 10;
|
|
|
|
switch(unit)
|
|
{
|
|
case > 1000000:
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_s_to_move_to_sleep_state,
|
|
unit / 1000000).
|
|
AppendLine();
|
|
|
|
break;
|
|
case > 1000:
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_ms_to_move_to_sleep_state,
|
|
unit / 1000).
|
|
AppendLine();
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_takes_a_maximum_of_0_μs_to_move_to_sleep_state, unit).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization.Device_has_0_sectors, csd.SectorCount).AppendLine();
|
|
|
|
if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported))
|
|
{
|
|
sb.AppendLine("\t" + Localization.Device_supports_secure_write_protection);
|
|
|
|
if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled))
|
|
sb.AppendLine("\t" + Localization.Device_has_secure_write_protection_enabled);
|
|
}
|
|
|
|
unit = csd.MinimumReadPerformance26 * 300;
|
|
|
|
if(csd.MinimumReadPerformance26 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumReadPerformance26_4 * 300;
|
|
|
|
if(csd.MinimumReadPerformance26_4 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_26Mhz_4_bit_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_26Mhz_4_bit_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumReadPerformance52 * 300;
|
|
|
|
if(csd.MinimumReadPerformance52 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_reading_in_SDR_52Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_SDR_52Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumReadPerformanceDDR52 * 600;
|
|
|
|
if(csd.MinimumReadPerformanceDDR52 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_4_8MB_s_reading_in_DDR_52Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_reading_in_DDR_52Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumWritePerformance26 * 300;
|
|
|
|
if(csd.MinimumWritePerformance26 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumWritePerformance26_4 * 300;
|
|
|
|
if(csd.MinimumWritePerformance26_4 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_26Mhz_4_bit_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_26Mhz_4_bit_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumWritePerformance52 * 300;
|
|
|
|
if(csd.MinimumWritePerformance52 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_2_4MB_s_writing_in_SDR_52Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_SDR_52Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
unit = csd.MinimumWritePerformanceDDR52 * 600;
|
|
|
|
if(csd.MinimumWritePerformanceDDR52 == 0)
|
|
sb.AppendLine("\t" + Localization.Device_cannot_achieve_4_8MB_s_writing_in_DDR_52Mhz_mode);
|
|
else
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_achieve_a_minimum_of_0_MB_s_writing_in_DDR_52Mhz_mode,
|
|
unit / 1000).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.PartitionSwitchingTime > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_take_a_maximum_of_0_ms_when_switching_partitions,
|
|
csd.PartitionSwitchingTime * 10).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.OutOfInterruptBusyTiming > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_can_take_a_maximum_of_0_ms_when_releasing_from_an_interrupt,
|
|
csd.OutOfInterruptBusyTiming * 10).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type0))
|
|
sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_zero);
|
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type1))
|
|
sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_one);
|
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type2))
|
|
sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_two);
|
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type3))
|
|
sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_three);
|
|
|
|
if(csd.DriverStrength.HasFlag(DriverStrength.Type4))
|
|
sb.AppendLine("\t" + Localization.Device_supports_IO_driver_strength_type_four);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_26))
|
|
sb.AppendLine("\t" + Localization.Device_supports_26_Mhz_mode);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_52))
|
|
sb.AppendLine("\t" + Localization.Device_supports_52_Mhz_mode);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52))
|
|
sb.AppendLine("\t" + Localization.Device_supports_DDR_52_Mhz_mode_at_1_8V_or_3V);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV))
|
|
sb.AppendLine("\t" + Localization.Device_supports_DDR_52_Mhz_mode_1_2V);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS200_18))
|
|
sb.AppendLine("\t" + Localization.Device_supports_HS_200_mode_SDR_200Mhz_at_1_8V);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS200_12))
|
|
sb.AppendLine("\t" + Localization.Device_supports_HS_200_mode_SDR_200Mhz_at_1_2V);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS400_18))
|
|
sb.AppendLine("\t" + Localization.Device_supports_HS_400_mode_DDR_200Mhz_at_1_8V);
|
|
|
|
if(csd.DeviceType.HasFlag(DeviceType.HS400_12))
|
|
sb.AppendLine("\t" + Localization.Device_supports_HS_400_mode_DDR_200Mhz_at_1_2V);
|
|
|
|
sb.AppendFormat("\t" + Localization.CSD_version_one_0_revision_one_1, csd.Structure, csd.Revision).AppendLine();
|
|
|
|
switch(csd.CommandSet)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_follows_compatibility_MMC_command_set);
|
|
|
|
break;
|
|
case 1:
|
|
switch(csd.CommandSetRevision)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_follows_standard_MMC_command_set_v4_0);
|
|
|
|
break;
|
|
default:
|
|
sb.
|
|
AppendFormat("\t" + Localization.Device_follows_standard_MMC_command_set_with_unknown_version_code_0,
|
|
csd.CommandSetRevision).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_follows_unknown_MMC_command_set_code_0_with_revision_code_1,
|
|
csd.CommandSet, csd.CommandSetRevision).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.HighSpeedInterfaceTiming & 0x0F)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_is_in_High_Speed_mode);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_is_in_HS200_mode);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_is_in_HS400_mode);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_has_unknown_timing_mode_0,
|
|
csd.HighSpeedInterfaceTiming & 0x0F).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
sb.AppendFormat("\t" + Localization.Selected_driver_strength_is_type_0,
|
|
(csd.HighSpeedInterfaceTiming & 0xF0) >> 4).
|
|
AppendLine();
|
|
|
|
if((csd.StrobeSupport & 0x01) == 0x01)
|
|
{
|
|
sb.AppendLine("\t" + Localization.Device_supports_enhanced_strobe_mode);
|
|
|
|
sb.AppendLine((csd.BusWidth & 0x80) == 0x80
|
|
? "\t" + Localization.Device_uses_strobe_during_Data_Out_CRC_and_CMD_responses
|
|
: "\t" + Localization.Device_uses_strobe_during_Data_Out_and_CRC_responses);
|
|
}
|
|
|
|
switch(csd.BusWidth & 0x0F)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_1bit_data_bus);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_4bit_data_bus);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_8bit_data_bus);
|
|
|
|
break;
|
|
case 5:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_4bit_DDR_data_bus);
|
|
|
|
break;
|
|
case 6:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_8bit_DDR_data_bus);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_is_using_unknown_data_bus_code_0, csd.BusWidth & 0x0F).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.ErasedMemoryContent)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
sb.AppendFormat("\t" + Localization.Erased_memory_range_shall_be_0, csd.ErasedMemoryContent).
|
|
AppendLine();
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Unknown_erased_memory_content_code_0, csd.ErasedMemoryContent).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
if((csd.PartitionConfiguration & 0x40) == 0x40)
|
|
sb.AppendLine("\t" + Localization.Device_sends_boot_acknowledge);
|
|
|
|
switch((csd.PartitionConfiguration & 0x38) >> 3)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_is_not_boot_enabled);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_boot_partition_one_is_enabled);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_boot_partition_two_is_enabled);
|
|
|
|
break;
|
|
case 7:
|
|
sb.AppendLine("\t" + Localization.Device_user_area_is_enable_for_boot);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Unknown_enabled_boot_partition_code_0,
|
|
(csd.PartitionConfiguration & 0x38) >> 3).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.PartitionConfiguration & 0x07)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.There_is_no_access_to_boot_partition);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.There_is_read_write_access_to_boot_partition_one);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.There_is_read_write_access_to_boot_partition_two);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.There_is_read_write_access_to_replay_protected_memory_block);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.There_is_access_to_general_purpose_partition_0,
|
|
(csd.PartitionConfiguration & 0x07) - 3).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
if(csd.BootConfigProtection.HasFlag(BootConfigProtection.Permanent))
|
|
sb.AppendLine("\t" + Localization.Change_of_the_boot_configuration_register_bits_is_permanently_disabled);
|
|
else if(csd.BootConfigProtection.HasFlag(BootConfigProtection.PowerCycle))
|
|
{
|
|
sb.AppendLine("\t" +
|
|
Localization.
|
|
Change_of_the_boot_configuration_register_bits_is_disabled_until_the_next_power_cycle);
|
|
}
|
|
|
|
switch(csd.BootBusConditions & 0x03)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x1_SDR_or_x4_DDR_bus_width);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x4_SDR_or_DDR_bus_width);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_will_boot_up_in_x8_SDR_or_DDR_bus_width);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Unknown_boot_condition_for_bus_width_with_code_three);
|
|
|
|
break;
|
|
}
|
|
|
|
sb.AppendLine((csd.BootBusConditions & 4) == 4
|
|
? "\t" + Localization.Device_will_retain_boot_conditions_after_boot_operation
|
|
: "\t" +
|
|
Localization.Device_will_reset_boot_conditions_to_compatibility_mode_after_boot_operation);
|
|
|
|
switch((csd.BootBusConditions & 0x24) >> 3)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" +
|
|
Localization.Device_will_use_single_data_rate_with_compatible_timings_in_boot_operation);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" +
|
|
Localization.Device_will_use_single_data_rate_with_high_speed_timings_in_boot_operation);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Device_will_use_dual_data_rate_in_boot_operation);
|
|
|
|
break;
|
|
case 3:
|
|
sb.AppendLine("\t" + Localization.Device_will_use_unknown_boot_mode_with_code_three);
|
|
|
|
break;
|
|
}
|
|
|
|
if(csd.HighCapacityEraseGroupDefinition.HasFlag(HighCapacityEraseGroupDefinition.Enabled))
|
|
{
|
|
sb.AppendLine("\t" +
|
|
Localization.
|
|
Device_will_use_high_capacity_erase_unit_size__timeout_and_write_protect_group_size_definitions);
|
|
}
|
|
|
|
switch(csd.BootWriteProtectionStatus & 0x03)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Boot_area_one_is_not_protected);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Boot_area_one_is_power_on_protected);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Boot_area_one_is_permanently_protected);
|
|
|
|
break;
|
|
}
|
|
|
|
switch((csd.BootWriteProtectionStatus & 0x0C) >> 2)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Boot_area_two_is_not_protected);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Boot_area_two_is_power_on_protected);
|
|
|
|
break;
|
|
case 2:
|
|
sb.AppendLine("\t" + Localization.Boot_area_two_is_permanently_protected);
|
|
|
|
break;
|
|
}
|
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Permanent))
|
|
{
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected))
|
|
{
|
|
sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.
|
|
PermanentArea2)
|
|
? "\t" + Localization.Boot_area_two_is_permanently_write_protected
|
|
: "\t" + Localization.Boot_area_one_is_permanently_write_protected);
|
|
}
|
|
else
|
|
sb.AppendLine("\t" + Localization.Both_boot_areas_are_permanently_write_protected);
|
|
}
|
|
else if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOn))
|
|
{
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected))
|
|
{
|
|
sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnArea2)
|
|
? "\t" + Localization.Boot_area_two_is_write_protected_until_next_power_cycle
|
|
: "\t" + Localization.Boot_area_one_is_write_protected_until_next_power_cycle);
|
|
}
|
|
else
|
|
sb.AppendLine("\t" + Localization.Both_boot_areas_are_write_protected_until_next_power_cycle);
|
|
}
|
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable))
|
|
sb.AppendLine("\t" + Localization.Permanent_write_protection_of_boot_areas_is_disabled);
|
|
|
|
if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable))
|
|
sb.AppendLine("\t" + Localization.Power_cycled_write_protection_of_boot_areas_is_disabled);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword))
|
|
sb.AppendLine("\t" + Localization.Use_of_password_protection_features_is_permanently_disabled);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect))
|
|
sb.AppendLine("\t" + Localization.Use_of_permanent_write_protection_is_disabled);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent))
|
|
sb.AppendLine("\t" + Localization.Permanent_write_protection_is_disabled);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn))
|
|
sb.AppendLine("\t" + Localization.Power_cycled_write_protection_is_disabled);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent))
|
|
sb.AppendLine("\t" + Localization.Permanent_write_protection_will_be_applied_to_selected_group);
|
|
|
|
if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn))
|
|
sb.AppendLine("\t" + Localization.Power_cycled_write_protection_will_be_applied_to_selected_group);
|
|
|
|
if((csd.FirmwareConfiguration & 0x01) == 0x01)
|
|
sb.AppendLine("\t" + Localization.Firmware_updates_are_permanently_disabled);
|
|
|
|
if(csd.RPMBSize > 0)
|
|
{
|
|
sb.AppendFormat("\t" + Localization.Device_has_a_0_KiB_replay_protected_memory_block, csd.RPMBSize * 128).
|
|
AppendLine();
|
|
}
|
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported))
|
|
{
|
|
sb.AppendLine("\t" + Localization.Device_supports_partitioning_features);
|
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced))
|
|
{
|
|
sb.AppendLine("\t" +
|
|
Localization.
|
|
Device_can_have_enhanced_technological_features_in_partitions_and_user_data_area);
|
|
}
|
|
|
|
if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended))
|
|
sb.AppendLine("\t" + Localization.Device_can_have_extended_partitions_attribute);
|
|
}
|
|
|
|
switch(csd.NativeSectorSize)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_natively_uses_512_byte_sectors);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_natively_uses_4096_byte_sectors);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_natively_uses_unknown_sector_size_indicated_by_code_0,
|
|
csd.NativeSectorSize).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.SectorSizeEmulation)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_is_emulating_512_byte_sectors);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_is_using_natively_sized_sectors);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_emulates_unknown_sector_size_indicated_by_code_0,
|
|
csd.NativeSectorSize).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
switch(csd.SectorSize)
|
|
{
|
|
case 0:
|
|
sb.AppendLine("\t" + Localization.Device_currently_addresses_512_byte_sectors);
|
|
|
|
break;
|
|
case 1:
|
|
sb.AppendLine("\t" + Localization.Device_currently_addresses_4096_byte_sectors);
|
|
|
|
break;
|
|
default:
|
|
sb.AppendFormat("\t" + Localization.Device_currently_addresses_unknown_sector_size_indicated_by_code_0,
|
|
csd.NativeSectorSize).
|
|
AppendLine();
|
|
|
|
break;
|
|
}
|
|
|
|
if((csd.CacheControl & 0x01) == 0x01)
|
|
sb.AppendLine("\t" + Localization.Devices_cache_is_enabled);
|
|
|
|
if((csd.CommandQueueModeEnable & 0x01) == 0x01)
|
|
sb.AppendLine("\t" + Localization.Device_has_enabled_command_queuing);
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response));
|
|
} |