From 91f85d461871912c22d5cc1f345df6468e111f9c Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 29 Sep 2017 06:09:49 +0000 Subject: [PATCH 1/5] Added vendor code for QEMU SecureDigital. --- DiscImageChef.Decoders/SecureDigital/VendorString.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiscImageChef.Decoders/SecureDigital/VendorString.cs b/DiscImageChef.Decoders/SecureDigital/VendorString.cs index 586d0fe53..7b2eb8ade 100644 --- a/DiscImageChef.Decoders/SecureDigital/VendorString.cs +++ b/DiscImageChef.Decoders/SecureDigital/VendorString.cs @@ -38,6 +38,8 @@ namespace DiscImageChef.Decoders.SecureDigital { switch(SDVendorID) { + case 0xAA: + return "QEMU"; default: return string.Format("Unknown manufacturer ID 0x{0:X2}", SDVendorID); } From 74e4dadbdcb49a8e6810d180e7d6e2d29fdcde04 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 29 Sep 2017 06:10:35 +0000 Subject: [PATCH 2/5] On QEMU's virtual SDHCI reading several commands at once it blocking the card right now, until I get real hardware and check out why it's better to be safe than sorry, so reading is limited to 1 block at a time. --- DiscImageChef.Core/Devices/Dumping/SecureDigital.cs | 2 +- DiscImageChef.Core/Devices/Scanning/SecureDigital.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs index f1ae5da33..326ccbf86 100644 --- a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs @@ -84,7 +84,7 @@ namespace DiscImageChef.Core.Devices.Dumping sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType(); - uint blocksToRead = 256; + uint blocksToRead = 1; uint blockSize = 512; ulong blocks = 0; byte[] cid = null; diff --git a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs index 084278e98..fd79162be 100644 --- a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs @@ -59,7 +59,7 @@ namespace DiscImageChef.Core.Devices.Scanning uint timeout = 5; double duration = 0; ushort currentProfile = 0x0001; - uint blocksToRead = 256; + uint blocksToRead = 1; uint blockSize = 512; if(dev.Type == DeviceType.MMC) From efb7331a9827d487ae77d378bfc94066e1ad4ef4 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 29 Sep 2017 12:49:08 +0000 Subject: [PATCH 3/5] Corrected byte addressing for MMC/SD. --- DiscImageChef.Core/Devices/Dumping/SecureDigital.cs | 11 ++++++++--- DiscImageChef.Core/Devices/Scanning/SecureDigital.cs | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs index 326ccbf86..b0152bc29 100644 --- a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs @@ -94,6 +94,7 @@ namespace DiscImageChef.Core.Devices.Dumping byte[] scr = null; uint[] response; int physicalBlockSize = 0; + bool byteAddressed = true; if(dev.Type == DeviceType.MMC) { @@ -111,6 +112,8 @@ namespace DiscImageChef.Core.Devices.Dumping physicalBlockSize = 512; else if(ecsdDecoded.NativeSectorSize == 1) physicalBlockSize = 4096; + // Supposing it's high-capacity MMC if it has Extended CSD... + byteAddressed = false; } else ecsd = null; @@ -142,6 +145,8 @@ namespace DiscImageChef.Core.Devices.Dumping csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd); blocks = (ulong)(csdDecoded.Structure == 0 ? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2) : (csdDecoded.Size + 1) * 1024); blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength); + // Structure >=1 for SDHC/SDXC, so that's block addressed + byteAddressed = csdDecoded.Structure == 0; } else csd = null; @@ -243,7 +248,7 @@ namespace DiscImageChef.Core.Devices.Dumping while(true) { - error = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, false, timeout, out duration); + error = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration); if(error) blocksToRead /= 2; @@ -295,7 +300,7 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed); - error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, false, timeout, out duration); + error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout, out duration); if(!error) { @@ -350,7 +355,7 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : ""); - error = dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, false, timeout, out duration); + error = dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout, out duration); totalDuration += duration; diff --git a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs index fd79162be..5a68ed0f3 100644 --- a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs @@ -61,6 +61,7 @@ namespace DiscImageChef.Core.Devices.Scanning ushort currentProfile = 0x0001; uint blocksToRead = 1; uint blockSize = 512; + bool byteAddressed = true; if(dev.Type == DeviceType.MMC) { @@ -74,6 +75,8 @@ namespace DiscImageChef.Core.Devices.Scanning blocksToRead = ecsd.OptimalReadSize; results.blocks = ecsd.SectorCount; blockSize = (uint)(ecsd.SectorSize == 1 ? 4096 : 512); + // Supposing it's high-capacity MMC if it has Extended CSD... + byteAddressed = false; } if(sense || results.blocks == 0) @@ -97,6 +100,8 @@ namespace DiscImageChef.Core.Devices.Scanning csd = Decoders.SecureDigital.Decoders.DecodeCSD(cmdBuf); results.blocks = (ulong)(csd.Structure == 0 ? (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) : (csd.Size + 1) * 1024); blockSize = (uint)Math.Pow(2, csd.ReadBlockLength); + // Structure >=1 for SDHC/SDXC, so that's block addressed + byteAddressed = csd.Structure == 0; } } @@ -110,7 +115,7 @@ namespace DiscImageChef.Core.Devices.Scanning while(true) { - sense = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, false, timeout, out duration); + sense = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration); if(sense) blocksToRead /= 2; @@ -180,7 +185,7 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, results.blocks, currentSpeed); - bool error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, false, timeout, out duration); + bool error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout, out duration); if(!error) { @@ -246,7 +251,7 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rSeeking to sector {0}...\t\t", seekPos); - dev.Read(out cmdBuf, out response, (uint)seekPos, blockSize, blocksToRead, false, timeout, out seekCur); + dev.Read(out cmdBuf, out response, (uint)seekPos, blockSize, blocksToRead, byteAddressed, timeout, out seekCur); #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(seekCur > results.seekMax && seekCur != 0) From a82071a3e37715c43671db54dd2f5b07d04b7681 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 29 Sep 2017 13:01:16 +0000 Subject: [PATCH 4/5] Solved reading multiple MMC/SD commands at a time. --- DiscImageChef.Core/Devices/Dumping/SecureDigital.cs | 2 +- DiscImageChef.Core/Devices/Scanning/SecureDigital.cs | 2 +- DiscImageChef.Devices/Device/MmcCommands/MMC.cs | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs index b0152bc29..d03852886 100644 --- a/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Dumping/SecureDigital.cs @@ -84,7 +84,7 @@ namespace DiscImageChef.Core.Devices.Dumping sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType(); - uint blocksToRead = 1; + uint blocksToRead = 128; uint blockSize = 512; ulong blocks = 0; byte[] cid = null; diff --git a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs index 5a68ed0f3..d2fa42035 100644 --- a/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs +++ b/DiscImageChef.Core/Devices/Scanning/SecureDigital.cs @@ -59,7 +59,7 @@ namespace DiscImageChef.Core.Devices.Scanning uint timeout = 5; double duration = 0; ushort currentProfile = 0x0001; - uint blocksToRead = 1; + uint blocksToRead = 128; uint blockSize = 512; bool byteAddressed = true; diff --git a/DiscImageChef.Devices/Device/MmcCommands/MMC.cs b/DiscImageChef.Devices/Device/MmcCommands/MMC.cs index 9f02a8a9f..7d64e20a6 100644 --- a/DiscImageChef.Devices/Device/MmcCommands/MMC.cs +++ b/DiscImageChef.Devices/Device/MmcCommands/MMC.cs @@ -127,7 +127,13 @@ namespace DiscImageChef.Devices error = lastError != 0; if(transferLength > 1) + { + byte[] foo = new byte[0]; + SendMmcCommand(MmcCommands.StopTransmission, false, false, MmcFlags.Response_R1b | MmcFlags.ResponseSPI_R1b | MmcFlags.CommandAC, + 0, 0, 0, ref foo, out uint[] responseStop, out double stopDuration, out bool stopSense, timeout); + duration += stopDuration; DicConsole.DebugWriteLine("MMC Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration); + } else DicConsole.DebugWriteLine("MMC Device", "READ_SINGLE_BLOCK took {0} ms.", duration); From bc72ff16420d08326f3232ef601e43d8b8a0e63a Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 29 Sep 2017 13:05:50 +0000 Subject: [PATCH 5/5] Starting with Linux 4.8 the SD/MMC OCR is shown also in /sys, so cache it if present. --- DiscImageChef.Devices/Device/Commands.cs | 13 +++++++++++++ DiscImageChef.Devices/Device/Constructor.cs | 6 ++++++ DiscImageChef.Devices/Device/Variables.cs | 1 + 3 files changed, 20 insertions(+) diff --git a/DiscImageChef.Devices/Device/Commands.cs b/DiscImageChef.Devices/Device/Commands.cs index c0e18e40f..cb93ca962 100644 --- a/DiscImageChef.Devices/Device/Commands.cs +++ b/DiscImageChef.Devices/Device/Commands.cs @@ -171,6 +171,19 @@ namespace DiscImageChef.Devices return 0; } + if((command == (MmcCommands)SecureDigitalCommands.SendOperatingCondition || + command == MmcCommands.SendOpCond) && cachedOcr != null) + { + System.DateTime start = System.DateTime.Now; + buffer = new byte[cachedOcr.Length]; + System.Array.Copy(cachedOcr, buffer, buffer.Length); + response = new uint[4]; + sense = false; + System.DateTime end = System.DateTime.Now; + duration = (end - start).TotalMilliseconds; + return 0; + } + return Command.SendMmcCommand(platformID, fd, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout); } diff --git a/DiscImageChef.Devices/Device/Constructor.cs b/DiscImageChef.Devices/Device/Constructor.cs index dfd593c65..1f820b573 100644 --- a/DiscImageChef.Devices/Device/Constructor.cs +++ b/DiscImageChef.Devices/Device/Constructor.cs @@ -211,6 +211,12 @@ namespace DiscImageChef.Devices if(len == 0) cachedScr = null; } + if(System.IO.File.Exists("/sys/block/" + devPath + "/device/ocr")) + { + int len = ConvertFromHexASCII("/sys/block/" + devPath + "/device/ocr", out cachedOcr); + if(len == 0) + cachedOcr = null; + } if(cachedCid != null) { diff --git a/DiscImageChef.Devices/Device/Variables.cs b/DiscImageChef.Devices/Device/Variables.cs index 97aec3590..5da1cb57b 100644 --- a/DiscImageChef.Devices/Device/Variables.cs +++ b/DiscImageChef.Devices/Device/Variables.cs @@ -67,6 +67,7 @@ namespace DiscImageChef.Devices readonly byte[] cachedCsd; readonly byte[] cachedCid; readonly byte[] cachedScr; + readonly byte[] cachedOcr; /// /// Gets the Platform ID for this device