Beispiel #1
0
        public static ExtendedCSD DecodeExtendedCSD(byte[] response)
        {
            if (response == null)
            {
                return(null);
            }

            if (response.Length != 512)
            {
                return(null);
            }

            GCHandle    handle = GCHandle.Alloc(response, GCHandleType.Pinned);
            ExtendedCSD csd    = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));

            handle.Free();

            return(csd);
        }
Beispiel #2
0
        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)
            {
                sb.AppendLine((csd.HPIFeatures & 0x02) == 0x02
                                  ? "\tDevice implements HPI using CMD12"
                                  : "\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");
                sb.AppendLine((csd.BusWidth & 0x80) == 0x80
                                  ? "\tDevice uses strobe during Data Out, CRC and CMD responses"
                                  : "\tDevice uses strobe during Data Out and CRC responses");
            }

            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());
        }