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