From 5b9b6fab59a42e089cd9d180e8eba32811513721 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 9 Dec 2020 20:11:12 +0000 Subject: [PATCH] Add more fields to MultiMediaCard's Extended CSD. --- MMC/ExtendedCSD.cs | 723 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 566 insertions(+), 157 deletions(-) diff --git a/MMC/ExtendedCSD.cs b/MMC/ExtendedCSD.cs index dd1d44755..b9c5ff333 100644 --- a/MMC/ExtendedCSD.cs +++ b/MMC/ExtendedCSD.cs @@ -88,128 +88,249 @@ namespace Aaru.Decoders.MMC public byte PartitionsAttribute; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] MaxEnhancedAreaSize; - public byte 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 byte UserAreaWriteProtectionRegister; - public byte Reserved5; - public byte BootAreaWriteProtectionRegister; - public byte BootWriteProtectionStatus; - public byte HighCapacityEraseGroupDefinition; - public byte Reserved6; - public byte BootBusConditions; - public byte 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 byte DeviceType; - public byte 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 byte 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 byte BootInformation; - public byte SecureTRIMMultiplier; - public byte SecureEraseMultiplier; - public byte 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 byte 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; + 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 byte CMDQueuingSupport; + 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 byte FFUFeatures; - public byte SupportedModes; - public byte ExtendedPartitionsSupport; - public byte LargeUnitSize; - public byte ContextManagementCaps; - public byte TagResourcesSize; - public byte TagUnitSize; - public byte DataTagSupport; - public byte MaxPackedWriteCommands; - public byte MaxPackedReadCommands; - public byte BackgroundOperationsSupport; - public byte HPIFeatures; - public byte SupportedCommandSets; - public byte ExtendedSecurityCommandsError; + 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 + } + + [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 @@ -236,39 +357,90 @@ namespace Aaru.Decoders.MMC double unit; - if((csd.HPIFeatures & 0x01) == 0x01) - sb.AppendLine((csd.HPIFeatures & 0x02) == 0x02 ? "\tDevice implements HPI using CMD12" + if(csd.ExtendedSecurityCommandsError != 0) + sb.AppendFormat("\tLast extended security error was {0}", csd.ExtendedSecurityCommandsError). + AppendLine(); + + if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard)) + sb.AppendLine("\tDevice supports standard MMC command set"); + + if(((int)csd.SupportedCommandSets & 0xFE) != 0) + sb.AppendFormat("\tDevice supports unknown command sets 0x{0:X2}", (int)csd.SupportedCommandSets); + + if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported)) + sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12) ? "\tDevice implements HPI using CMD12" : "\tDevice implements HPI using CMD13"); - if((csd.BackgroundOperationsSupport & 0x01) == 0x01) + if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported)) sb.AppendLine("\tDevice supports background operations"); sb.AppendFormat("\tDevice supports a maximum of {0} packed reads and {1} packed writes", csd.MaxPackedReadCommands, csd.MaxPackedWriteCommands).AppendLine(); - if((csd.DataTagSupport & 0x01) == 0x01) + 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(); } - if((csd.ExtendedPartitionsSupport & 0x01) == 0x01) + if(csd.ContextManagementCaps != 0) + { + sb.AppendFormat("\tMax context ID is {0}.", csd.ContextManagementCaps & 0xF).AppendLine(); + + sb.AppendFormat("\tLarge unit maximum multiplier is {0}.", + ((csd.ContextManagementCaps & 0x70) >> 4) + 1).AppendLine(); + } + + sb.AppendFormat("\tLarge unit size is {0} MiB", csd.LargeUnitSize + 1).AppendLine(); + + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent)) sb.AppendLine("\tDevice supports non-persistent extended partitions"); - if((csd.ExtendedPartitionsSupport & 0x02) == 0x02) + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode)) sb.AppendLine("\tDevice supports system code extended partitions"); - if((csd.SupportedModes & 0x01) == 0x01) + if(csd.SupportedModes.HasFlag(SupportedModes.FFU)) + { sb.AppendLine("\tDevice supports FFU"); - if((csd.SupportedModes & 0x02) == 0x02) + if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes)) + { + // todo public byte ModeOperationCodes + + if(csd.OperationCodesTimeout > 0) + { + unit = Math.Pow(2, csd.OperationCodesTimeout) * 100; + + if(unit > 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(); + else if(unit > 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(); + else + sb. + AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs", + unit).AppendLine(); + } + } + } + + if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific)) sb.AppendLine("\tDevice supports Vendor Specific Mode"); - if((csd.CMDQueuingSupport & 0x01) == 0x01) + if(csd.BarrierSupport == 0x01) + { + sb.AppendLine("\tDevice supports the barrier command"); + } + + if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported)) sb.AppendFormat("\tDevice supports command queuing with a depth of {0}", csd.CMDQueuingDepth + 1). AppendLine(); - sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberofFWSectorsCorrectlyProgrammed). + sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberOfFWSectorsCorrectlyProgrammed). AppendLine(); switch(csd.DeviceLifeEstimationTypeB) @@ -383,9 +555,21 @@ namespace Aaru.Decoders.MMC 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(); + 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(); + + 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(); + + 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(); sb.AppendFormat("\tDevice version: {0}", csd.DeviceVersion).AppendLine(); sb.AppendFormat("\tFirmware version: {0}", csd.FirmwareVersion).AppendLine(); @@ -393,7 +577,7 @@ namespace Aaru.Decoders.MMC if(csd.CacheSize == 0) sb.AppendLine("\tDevice has no cache"); else - sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize).AppendLine(); + sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize / 8).AppendLine(); if(csd.GenericCMD6Timeout > 0) sb.AppendFormat("\tDevice takes a maximum of {0} ms by default for a SWITCH command", @@ -431,23 +615,23 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice takes a maximum of {0} ms for initialization after partition", csd.InitializationTimeAfterPartition * 100).AppendLine(); - if((csd.CacheFlushingPolicy & 0x01) == 0x01) + if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO)) sb.AppendLine("\tDevice uses a FIFO policy for cache flushing"); if(csd.TRIMMultiplier > 0) sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group", csd.TRIMMultiplier * 300).AppendLine(); - if((csd.SecureFeatureSupport & 0x40) == 0x40) + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize)) sb.AppendLine("\tDevice supports the sanitize operation"); - if((csd.SecureFeatureSupport & 0x10) == 0x10) + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim)) sb.AppendLine("\tDevice supports supports the secure and insecure trim operations"); - if((csd.SecureFeatureSupport & 0x04) == 0x04) + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective)) sb.AppendLine("\tDevice supports automatic erase on retired defective blocks"); - if((csd.SecureFeatureSupport & 0x01) == 0x01) + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge)) sb.AppendLine("\tDevice supports secure purge operations"); if(csd.SecureEraseMultiplier > 0) @@ -458,21 +642,21 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely trimming a single erase group", csd.SecureTRIMMultiplier * 300).AppendLine(); - if((csd.BootInformation & 0x04) == 0x04) + if(csd.BootInformation.HasFlag(BootInformation.HighSpeed)) sb.AppendLine("\tDevice supports high speed timing on boot"); - if((csd.BootInformation & 0x02) == 0x02) + if(csd.BootInformation.HasFlag(BootInformation.DDR)) sb.AppendLine("\tDevice supports dual data rate on boot"); - if((csd.BootInformation & 0x01) == 0x01) + if(csd.BootInformation.HasFlag(BootInformation.Alternative)) sb.AppendLine("\tDevice supports alternative boot method"); if(csd.BootPartitionSize > 0) sb.AppendFormat("\tDevice has a {0} KiB boot partition", csd.BootPartitionSize * 128).AppendLine(); if((csd.AccessSize & 0x0F) > 0) - sb.AppendFormat("\tDevice has a page size of {0} KiB", (csd.AccessSize & 0x0F) * 512.0 / 1024.0). - AppendLine(); + sb.AppendFormat("\tDevice has a page size of {0} KiB", + 512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0).AppendLine(); if(csd.HighCapacityEraseUnitSize > 0) sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine(); @@ -551,15 +735,15 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice has {0} sectors", csd.SectorCount).AppendLine(); - if((csd.SecureWriteProtectInformation & 0x01) == 0x01) + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported)) { sb.AppendLine("\tDevice supports secure write protection"); - if((csd.SecureWriteProtectInformation & 0x02) == 0x02) + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled)) sb.AppendLine("\tDevice has secure write protection enabled"); } - unit = csd.MinimumReadPerformance26 * 150; + unit = csd.MinimumReadPerformance26 * 300; if(csd.MinimumReadPerformance26 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz mode"); @@ -567,7 +751,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode", unit / 1000). AppendLine(); - unit = csd.MinimumReadPerformance26_4 * 150; + unit = csd.MinimumReadPerformance26_4 * 300; if(csd.MinimumReadPerformance26_4 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode"); @@ -575,7 +759,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode", unit / 1000).AppendLine(); - unit = csd.MinimumReadPerformance52 * 150; + unit = csd.MinimumReadPerformance52 * 300; if(csd.MinimumReadPerformance52 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 52Mhz mode"); @@ -583,7 +767,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode", unit / 1000). AppendLine(); - unit = csd.MinimumReadPerformanceDDR52 * 300; + unit = csd.MinimumReadPerformanceDDR52 * 600; if(csd.MinimumReadPerformanceDDR52 == 0) sb.AppendLine("\tDevice cannot achieve 4.8MB/s reading in DDR 52Mhz mode"); @@ -591,7 +775,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode", unit / 1000). AppendLine(); - unit = csd.MinimumWritePerformance26 * 150; + unit = csd.MinimumWritePerformance26 * 300; if(csd.MinimumWritePerformance26 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz mode"); @@ -599,7 +783,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode", unit / 1000). AppendLine(); - unit = csd.MinimumWritePerformance26_4 * 150; + unit = csd.MinimumWritePerformance26_4 * 300; if(csd.MinimumWritePerformance26_4 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode"); @@ -607,7 +791,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode", unit / 1000).AppendLine(); - unit = csd.MinimumWritePerformance52 * 150; + unit = csd.MinimumWritePerformance52 * 300; if(csd.MinimumWritePerformance52 == 0) sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 52Mhz mode"); @@ -615,7 +799,7 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode", unit / 1000). AppendLine(); - unit = csd.MinimumWritePerformanceDDR52 * 300; + unit = csd.MinimumWritePerformanceDDR52 * 600; if(csd.MinimumWritePerformanceDDR52 == 0) sb.AppendLine("\tDevice cannot achieve 4.8MB/s writing in DDR 52Mhz mode"); @@ -631,32 +815,100 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt", csd.OutOfInterruptBusyTiming * 10).AppendLine(); - if((csd.DeviceType & 0x01) == 0x01) + if(csd.DriverStrength.HasFlag(DriverStrength.Type0)) + sb.AppendLine("\tDevice supports I/O driver strength type 0."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type1)) + sb.AppendLine("\tDevice supports I/O driver strength type 1."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type2)) + sb.AppendLine("\tDevice supports I/O driver strength type 2."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type3)) + sb.AppendLine("\tDevice supports I/O driver strength type 3."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type4)) + sb.AppendLine("\tDevice supports I/O driver strength type 4."); + + if(csd.DeviceType.HasFlag(DeviceType.HS_26)) sb.AppendLine("\tDevice supports 26 Mhz mode"); - if((csd.DeviceType & 0x02) == 0x02) + if(csd.DeviceType.HasFlag(DeviceType.HS_52)) sb.AppendLine("\tDevice supports 52 Mhz mode"); - if((csd.DeviceType & 0x04) == 0x04) + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52)) sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V"); - if((csd.DeviceType & 0x08) == 0x08) + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV)) sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V"); - if((csd.DeviceType & 0x10) == 0x10) + if(csd.DeviceType.HasFlag(DeviceType.HS200_18)) sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V"); - if((csd.DeviceType & 0x20) == 0x20) + if(csd.DeviceType.HasFlag(DeviceType.HS200_12)) sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V"); - if((csd.DeviceType & 0x40) == 0x40) + if(csd.DeviceType.HasFlag(DeviceType.HS400_18)) sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V"); - if((csd.DeviceType & 0x80) == 0x80) + if(csd.DeviceType.HasFlag(DeviceType.HS400_12)) sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.2V"); sb.AppendFormat("\tCSD version 1.{0} revision 1.{1}", csd.Structure, csd.Revision).AppendLine(); + switch(csd.CommandSet) + { + case 0: + sb.AppendLine("\tDevice follows compatibility MMC command set."); + + break; + case 1: + switch(csd.CommandSetRevision) + { + case 0: + sb.AppendLine("\tDevice follows standard MMC command set v4.0."); + + break; + default: + sb.AppendFormat("\tDevice follows standard MMC command set with unknown version code {0}.", + csd.CommandSetRevision).AppendLine(); + + break; + } + + break; + default: + sb.AppendFormat("\tDevice 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("\tDevice is in High Speed mode."); + + break; + case 2: + sb.AppendLine("\tDevice is in HS-200 mode."); + + break; + case 3: + sb.AppendLine("\tDevice is in HS-400 mode."); + + break; + default: + sb.AppendFormat("\tDevice has unknown timing mode {0}.", csd.HighSpeedInterfaceTiming & 0x0F). + AppendLine(); + + break; + } + + sb.AppendFormat("\tSelected driver strength is type {0}.", (csd.HighSpeedInterfaceTiming & 0xF0) >> 4). + AppendLine(); + if((csd.StrobeSupport & 0x01) == 0x01) { sb.AppendLine("\tDevice supports enhanced strobe mode"); @@ -694,7 +946,20 @@ namespace Aaru.Decoders.MMC break; } - if((csd.PartitionConfiguration & 0x80) == 0x80) + switch(csd.ErasedMemoryContent) + { + case 0: + case 1: + sb.AppendFormat("\tErased memory range shall be '{0}'.", csd.ErasedMemoryContent).AppendLine(); + + break; + default: + sb.AppendFormat("\tUnknown erased memory content code {0}", csd.ErasedMemoryContent).AppendLine(); + + break; + } + + if((csd.PartitionConfiguration & 0x40) == 0x40) sb.AppendLine("\tDevice sends boot acknowledge"); switch((csd.PartitionConfiguration & 0x38) >> 3) @@ -747,6 +1012,139 @@ namespace Aaru.Decoders.MMC break; } + 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."); + + switch(csd.BootBusConditions & 0x03) + { + case 0: + sb.AppendLine("\tDevice will boot up in x1 SDR or x4 DDR bus width."); + + break; + case 1: + sb.AppendLine("\tDevice will boot up in x4 SDR or DDR bus width."); + + break; + case 2: + sb.AppendLine("\tDevice will boot up in x8 SDR or DDR bus width."); + + break; + case 3: + sb.AppendLine("\tUnknown boot condition for bus width with code 3."); + + break; + } + + sb.AppendLine((csd.BootBusConditions & 4) == 4 + ? "\tDevice will retain boot conditions after boot operation." + : "\tDevice will reset boot conditions to compatibility mode after boot operation."); + + switch((csd.BootBusConditions & 0x24) >> 3) + { + case 0: + sb.AppendLine("\tDevice will use single data rate with compatible timings in boot operation."); + + break; + case 1: + sb.AppendLine("\tDevice will use single data rate with high speed timings in boot operation."); + + break; + case 2: + sb.AppendLine("\tDevice will use dual data rate in boot operation."); + + 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; + } + + 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)) + { + sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister. + PowerOnArea2) + ? "\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."); + } + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable)) + sb.AppendLine("\tPermanent write protection of boot areas is disabled."); + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable)) + sb.AppendLine("\tPower cycled write protection of boot areas is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword)) + sb.AppendLine("\tUse of password protection features is permanently disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect)) + sb.AppendLine("\tUse of permanent write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent)) + sb.AppendLine("\tPermanent write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn)) + sb.AppendLine("\tPower cycled write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent)) + sb.AppendLine("\tPermanent write protection will be applied to selected group."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn)) + sb.AppendLine("\tPower cycled write protection will be applied to selected group."); + if((csd.FirmwareConfiguration & 0x01) == 0x01) sb.AppendLine("\tFirmware updates are permanently disabled"); @@ -754,6 +1152,17 @@ namespace Aaru.Decoders.MMC sb.AppendFormat("\tDevice has a {0} KiB replay protected memory block", csd.RPMBSize * 128). AppendLine(); + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported)) + { + sb.AppendLine("\tDevice supports partitioning features"); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced)) + sb.AppendLine("\tDevice can have enhanced technological features in partitions and user data area"); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended)) + sb.AppendLine("\tDevice can have extended partitions attribute."); + } + switch(csd.NativeSectorSize) { case 0: