Ok, here goes. It's pretty huge, so I'll just post the important bits and post a download link to the source at the bottom. I've not yet started on getting overlap to work. YOU HAVE TO SET THE BUILD TARGET TO x86. (if you have an express edition then you'll need to expose the configuration manager first - its in the settings somewhere - "show advanced build options" or something).
(Remember this is Windows XP/Vista, Admin privileges required, build target must be x86, SD card must be attached via an SD reader connected directly to the PCI host - no USB reader...)
First up...
ENUMS - Boring they are in the header files in the WDK
// SD_COMMAND_CLASS public enum SdCommandClass : uint { Standard, // SDCC_STANDARD AppCmd // SDCC_APP_CMD }; // SD_TRANSFER_DIRECTION public enum SdTransferDirection : uint { Unspecified, // SDTD_UNSPECIFIED Read, // SDTD_READ Write // SDTD_WRITE }; // SD_TRANSFER_TYPE public enum SdTransferType : uint { Unspecified, // SDTT_UNSPECIFIED CmdOnly, // SDTT_CMD_ONLY SingleBlock, // SDTT_SINGLE_BLOCK MultiBlock, // SDTT_MULTI_BLOCK MultiBlockNoCmd12 // SDTT_MULTI_BLOCK_NO_CMD12 }; // SD_RESPONSE_TYPE public enum SdResponseType : uint { Unspecified, // SDRT_UNSPECIFIED None, // SDRT_NONE R1, // SDRT_1 R1b, // SDRT_1B R2, // SDRT_2 R3, // SDRT_3 R4, // SDRT_4 R5, // SDRT_5 R5b, // SDRT_5B R6 // SDRT_6 }; // SFFDISK_DCMD public enum SffdiskDcmd : uint { GetVersion, // SFFDISK_DC_GET_VERSION LockChannel, // SFFDISK_DC_LOCK_CHANNEL UnlockChannel, // SFFDISK_DC_UNLOCK_CHANNEL DeviceCommand // SFFDISK_DC_DEVICE_COMMAND };
public enum IoCtlCode : uint { SffdiskQueryDeviceProtocol = 0x71E80, // IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL SffdiskDeviceCommand = 0x79E84, // IOCTL_SFFDISK_DEVICE_COMMAND VolumeGetVolumeDiskExtents = 0x560000 // IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS };
Native Methods - There are plenty of overrides of DeviceIOControl. The last one that takes byte[] sends the sd command. Note the use of SafeHandles instead of IntPtr.
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] public extern static SafeFileHandle CreateFile(String fileName, AccessRights desiredAccess, ShareModes shareMode, IntPtr securityAttributes, CreationDisposition creationDisposition, int flagsAndAttributes, IntPtr hTemplateFile); // overload used for querydeviceprotocol [DllImport("kernel32", SetLastError = true)] public extern static bool DeviceIoControl(SafeFileHandle hVol, IoCtlCode controlCode, IntPtr inBuffer, int inBufferSize, ref SffdiskQueryDeviceProtocolData outBuffer, int outBufferSize, out int bytesReturned, IntPtr overlapped); // overload used for getting the disk extents [DllImport("kernel32", SetLastError = true)] public extern static bool DeviceIoControl(SafeFileHandle hVol, IoCtlCode controlCode, IntPtr inBuffer, int inBufferSize, out DiskExtents outBuffer, int outBufferSize, out int bytesReturned, IntPtr overlapped); // overload used for getting more than 1 diskextent [DllImport("kernel32", SetLastError = true)] public extern static bool DeviceIoControl(SafeFileHandle hVol, IoCtlCode controlCode, IntPtr inBuffer,int inBufferSize, IntPtr outBuffer, int outBufferSize, out int bytesReturned, IntPtr overlapped); // Overload for the CID [DllImport("kernel32", SetLastError = true)] public extern static bool DeviceIoControl(SafeFileHandle hVol, IoCtlCode controlCode, Byte[] inBuffer, int inBufferSize, Byte[] outBuffer, int outBufferSize, out int bytesReturned, IntPtr ovelapped);
The Structures - No fancy marshaling required. Again, see the WDK header files.
// SDCMD_DESCRIPTOR [StructLayout(LayoutKind.Sequential)] struct SdCmdDescriptor { public Byte CommandCode; public SdCommandClass CmdClass; public SdTransferDirection TransferDirection; public SdTransferType TransferType; public SdResponseType ResponseType; public int GetSize() { return Marshal.SizeOf(this); } }
// SFFDISK_DEVICE_COMMAND_DATA [StructLayout(LayoutKind.Sequential)] struct SffdiskDeviceCommandData { public ushort Size; // 0 public ushort Reserved; // 2 public SffdiskDcmd Command; // 4 public ushort ProtocolArgumentSize; // 8 public uint DeviceDataBufferSize; // 12 public uint Information; // 16 *ULONG_PTR*, Data[] Follows. public void Init() { this.Size = (ushort)Marshal.SizeOf(this); } }
// SFFDISK_QUERY_DEVICE_PROTOCOL_DATA [StructLayout(LayoutKind.Sequential)] struct SffdiskQueryDeviceProtocolData { public ushort Size; public ushort Reserved; public Guid ProtocolGuid; public void Init() { this.Size = (ushort)Marshal.SizeOf(this); } }
The class that makes the call - could do with more tidying up. CID and CSD are classes with lots of properties, the constructor takes the byte array returned by the deviceIOControl call and fills in the properties. They probably have mistakes too. See the linked code.
using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace JDMcF.SDCard { // This class might get some information about an SDCard. // Does not work with USB SD Card Readers. // Does not work with some SD Bus Host Drivers. // Administrator privileges required. // I don't know if the IOCTLs work with mobile devices. // I don't know if I'm translating the bytes from the CID correctly. public class SDCard { // GUID_SFF_PROTOCOL_SD private static readonly Guid GuidSffProtocolSd = new Guid("AD7536A8-D055-4C40-AA4D-96312DDB6B38"); private CID cid; public CID CID { get { return cid; } } private CSD csd; public CSD CSD { get { return csd; } } private DriveInfo driveInfo; public DriveInfo DriveInfo { get { return driveInfo; } } private string physicalDrivePath; public string PhysicalDrivePath { get { return physicalDrivePath; } } private SDCard(string physicalDrivePath, DriveInfo driveInfo) { // At first only these are initialised. It takes a second or so to // read the CID so we so // it on another thread and raise an event once done. this.physicalDrivePath = physicalDrivePath; this.driveInfo = driveInfo; } public static List<SDCard> GetSDCards() { List<SDCard> cards = new List<SDCard>(); // There are probably ways to mount the card elsewhere, // so it might miss those... foreach (DriveInfo di in System.IO.DriveInfo.GetDrives()) { // Are all SD Cards Removable? I don't know! if (di.DriveType == DriveType.Removable) { // We are enumerating volumes. Volumes can span physical // disks. Work out how many physical disks are involved // with each volume. (seems unlikely, but I just figured // out how to do this so what the heck)... List<string> physicalPaths = VolumeInfo.GetPhysicalDriveStrings(di); foreach (string physicalPath in physicalPaths) { if (IsSD(physicalPath)) { cards.Add(new SDCard(physicalPath, di)); } } } } return cards; } // Send IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL to see if the handle // belongs to an SD Card. private static bool IsSD(string physicalPath) { SafeFileHandle hVol = null; try { hVol = NativeMethods.CreateFile(physicalPath, AccessRights.GenericRead, ShareModes.FileShareRead ShareModes.FileShareWrite, IntPtr.Zero, CreationDisposition.OpenExisting, 0, IntPtr.Zero); if (hVol.IsInvalid) { throw new Win32Exception("Couldn't CreateFile for " + physicalPath); SffdiskQueryDeviceProtocolData queryData1 = new SffdiskQueryDeviceProtocolData(); queryData1.Init(); int bytesReturned; bool result = NativeMethods.DeviceIoControl(hVol, IoCtlCode.SffdiskQueryDeviceProtocol, IntPtr.Zero, 0, ref queryData1, queryData1.Size, out bytesReturned, IntPtr.Zero); return queryData1.ProtocolGuid.Equals(GuidSffProtocolSd); } finally { if (hVol != null) { if (!hVol.IsInvalid) { hVol.Close(); } hVol.Dispose(); } } } public void RefreshData() { GetRegister(Register.CID); GetRegister(Register.CSD); } // Send the command in the array. On return the array will have any // response. private void SendCommand(byte[] command) { SafeFileHandle hVol = null; try { hVol = NativeMethods.CreateFile(PhysicalDrivePath, AccessRights.GenericRead AccessRights.GenericWrite, ShareModes.FileShareRead ShareModes.FileShareWrite, IntPtr.Zero, CreationDisposition.OpenExisting, 0, IntPtr.Zero); int bytesReturned; bool result = NativeMethods.DeviceIoControl(hVol, IoCtlCode.SffdiskDeviceCommand, command, command.Length, command, command.Length, out bytesReturned, IntPtr.Zero); if (!result) throw new Win32Exception(); } finally { if (hVol != null) { if (!hVol.IsInvalid) { hVol.Close(); } hVol.Dispose(); } } } // Get the CID or CSD. They are almost identical commands... private void GetRegister(Register register) { byte[] command = null; SffdiskDeviceCommandData commandData = new SffdiskDeviceCommandData(); SdCmdDescriptor commandDescriptor = new SdCmdDescriptor(); commandData.Init(); commandData.Command = SffdiskDcmd.DeviceCommand; commandData.ProtocolArgumentSize = (ushort)commandDescriptor.GetSize(); commandData.DeviceDataBufferSize = 16; commandDescriptor.CommandCode = (byte)register; // <--- Not what the documentation indicates! commandDescriptor.CmdClass = SdCommandClass.Standard; commandDescriptor.TransferDirection = SdTransferDirection.Read; commandDescriptor.TransferType = SdTransferType.CmdOnly; commandDescriptor.ResponseType = SdResponseType.R2; // Now get the structs into the byte[] command = new byte[commandData.Size + commandData.ProtocolArgumentSize + commandData.DeviceDataBufferSize]; IntPtr hBuf = Marshal.AllocHGlobal(command.Length); Marshal.StructureToPtr(commandData, hBuf, true); IntPtr descriptorOffset = new IntPtr(hBuf.ToInt32() + commandData.Size); Marshal.StructureToPtr(commandDescriptor, descriptorOffset, true); Marshal.Copy(hBuf, command, 0, command.Length); Marshal.FreeHGlobal(hBuf); SendCommand(command); // Strip out the return bytes that live at the end of the command byte array. byte[] regBytes = new byte[16]; Buffer.BlockCopy(command, command.Length - 16, regBytes, 0, 16); if (register == Register.CID) { cid = new CID(regBytes); } else { csd = new CSD(regBytes); } } } }
Formatting is awful...
I tried this but it didn't work for me. Can you help me out please. I have a sony VAIO and the SD reader is built-in the system.
ReplyDeleteRegards
Hi,
ReplyDeleteI am getting error 50, "The request is not supported" in function IsSD() - any idea why? The SD I am interrogating is actually a GPS device connected via USB cable, and it mounts two Removable drives, G: and I:.
I read the note about it not working unless it's connected to the PCI bus, could that be the reason? If yes, isn't that a little limited? And how can one go about getting the CID for any type of SD card, be it in built-in readers or USB readers?
Many thanks,
Michael.
Hi,
ReplyDeleteThe download link is failed. Could you please mail it to me? Thanks~~
Schumi
Sorry, It's my network issue. I can download it now. Thanks.
ReplyDeletecan you pleas provide source code to download??
ReplyDeleteHi.
ReplyDeleteIs it impossible to get CID of SD card which is connected to USB reader?
If so, are there no way to identify SD card physically?
I have tried this code and I've got this output:
ReplyDelete\\.\PhysicalDrive3 I:\
--------------------
Raw CID Bytes: 00-00-00-00-06-00-00-00-60-48-A4-6E-10-00-3F-00
--------------------
Manufacturer ID: 3f
OEM ID:
Product Name: nH`
Product Revision: 0.0
Product Serial Number: 00060000
Manufacture Date: 0/2000
--------------------
Raw CSD Bytes: 00-00-00-00-06-00-00-00-60-48-A4-6E-10-00-3F-00
--------------------
CSD Version 2 bit value: CSD Version 1.0
Data Read Access Time 1 (TAAC):
Data Read Access Time 2 (NSAC): 16
Max Data Transfer Rate: 0
Card Command Classes: 101001000100
Max Read Data Block Length: 8
Partial Blocks For Read Allowed: False
Write Block Misalignment: True
Read Block Misalignment: True
DSR Implemented: False
Device Size: 0
Max Read Current @ VDD Min: 0.5mA
Max Read Current @ VDD Max: 1mA
Max Write Current @ VDD Min: 0.5mA
Max Write Current @ VDD Max: 1mA
Device Size Multiplier: 2
Erase Single Block Enable: False
Erase Sector Size: 13
Write Protect Group Size: 1
Write Protect Group Enable: False
Write Speed Factor: 1
Max Write Data Block Length: 2^0
Partial Blocks For Write Allowed: False
File Format Group: False
Copy Flag (OTP): False
Permanent Write Protection: False
Temporary Write Protection: False
File Format: 0
When I check on the SD bus I cannot see the CMD9 and CMD10 translated correctly.
Anyone can help?
MiKL~
i tried one or more times but .still now not completed.
DeleteHi,
ReplyDeleteI was writing program in C++ to read CID register. The procedure I have followed is but I am facing the same issue which I see that other people are also seeing.." I get 15 bytes of CID with a 00 in front and no CRC."
Were you able to root cause the reason for the same. Even when reading the whole buffer, this value is not there itself.
Regards,
Rakendra
Hi could someone provide the source code. I don't seem to be able to find the link. Thanks.
ReplyDeleteThanks found the link... I'll report any success.
DeleteHi!
ReplyDeleteLooking for a solution to read extended CSD (512 bytes) of eMMC devices.
CID / CSD can be accessed and in theory CMD8 (SEND_EXT_CSD) should work but no luck...
Do you have any suggestions?
Thanks so much in advance!!
The address link for the download is https://6zkatq.bl3301.livefilestore.com/y3mcs8fLISmDm5mpRPj_eqQ0_h_Sag4Nh2phG93llQDc35jy4Z5qkMQXUea2rTLBK3TmpRwCOv3tN42oA9g0ASiJZrY-RZfxm69zXIyzi1KubBGRxtECeLRTe2Nih4IXmMJ6qszQt90CgCfg05u3doYOg/JDMcF.SDCard.zip?download&psid=1
ReplyDeleteThe webpage seems to loose the link to the source when a new comment is added.
http://dropbox.com/sh/og6qm14hq4r0cvk/AAB_Mu7gBt6rcZbGM-0oBmuCa?dl=0
DeleteReadCID.exe & JDMcF.SDCard-src.zip
Got it from: https://onedrive.live.com/?id=862DEE3EC267CB5C
Modded it so IsSD() always returns true.
... and added error message output for GetLastError, if DeviceIoControl fails.
Attentions if you see error message at the beginning, the following will probably wrong!
Well DeviceIoControl( SffdiskQueryDeviceProtocol ...) is the critical point, doesn't get it work with my
PCI\VEN_104C&DEV_803B Texas Instruments PCIxx12 Integrated FlashMedia Controller
[TiFm21.sys 2.0.10 2009]
on Win7Sp1 X64
However with the error messages you might get I tiny bit more a clue what is not working and how to fix it.
Some Appendix
DeleteI found that SffdiskQueryDeviceProtocol = 0x71E80 Dword in \Windows\SYSTEM32\drivers\sffdisk.sys
It's the 'SFF Storage Class Driver' (Small Form Factor Disk Driver) from Microsoft 6.1.7600.16385 (win7_rtm.090713-1255) from about 2009.
I decompiled it with IDA ...
...
if ( DeviceIoControlCMD == SffdiskQueryDeviceProtocol )
{
if ( *(input + 8) < 0x14u )
goto STATUS_BUFFER_TOO_SMALL;
Result1 = (*(Arg1_0x40 + 0xA0))(*(Arg1_0x40 + 0x98), 6i64, 20i64, *(a2 + 0x18));
goto PreExit1;
}
...
and indeed thats sffdisk.sys is somehow involved on driver level to get DeviceIoControl( SffdiskQueryDeviceProtocol ...) and do something about it.
But well when I put my SDCard into the reader and check via
C:\>sc query sffdisk
The status of sffdisk it says it's not running.
Well if it is working on ya PC could you please check via the command above if sffdisk is running on ya PC if you've put in some card into the reader?
TIA
This comment has been removed by the author.
ReplyDeleteWhere is download link?
ReplyDeleteHas anybody attempted to get this running lately? I have run this on my Windows 10 machine in VS2015, but I get only 'empty' output for all removable devices:
ReplyDeleteSffdiskQueryDeviceProtocol ( \\.\PhysicalDrive2 ) -> ERR: A device attached to the system is not functioning (31)
SffdiskQueryDeviceProtocol ( \\.\PhysicalDrive3 ) -> ERR: The request is not supported (50)
\\.\PhysicalDrive2 E:\
--------------------
Raw CID Bytes: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
--------------------
Manufacturer ID: 0
OEM ID:
Product Name:
Product Revision: 0.0
Product Serial Number: 00000000
Manufacture Date: 0/2000
--------------------
Raw CSD Bytes: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
--------------------
CSD Version 2 bit value: CSD Version 1.0
Data Read Access Time 1 (TAAC):
Data Read Access Time 2 (NSAC): 0
Max Data Transfer Rate:
Card Command Classes: 000000000000
Max Read Data Block Length: 0
Partial Blocks For Read Allowed: False
Write Block Misalignment: False
Read Block Misalignment: False
DSR Implemented: False
Device Size: 0
Max Read Current @ VDD Min: 0.5mA
Max Read Current @ VDD Max: 1mA
Max Write Current @ VDD Min: 0.5mA
Max Write Current @ VDD Max: 1mA
Device Size Multiplier: 2
Erase Single Block Enable: False
Erase Sector Size: 1
Write Protect Group Size: 1
Write Protect Group Enable: False
Write Speed Factor: 1
Max Write Data Block Length: 2^0
Partial Blocks For Write Allowed: False
File Format Group: False
Copy Flag (OTP): False
Permanent Write Protection: False
Temporary Write Protection: False
File Format: 0
\\.\PhysicalDrive3 F:\
SffdiskDeviceCommand ( Cmd...) -> ERR: The request is not supported (50)
SffdiskDeviceCommand ( Cmd...) -> ERR: The request is not supported (50)
--------------------
Raw CID Bytes: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
--------------------
Manufacturer ID: 0
OEM ID:
Product Name:
Product Revision: 0.0
Product Serial Number: 00000000
Manufacture Date: 0/2000
--------------------
Raw CSD Bytes: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
--------------------
CSD Version 2 bit value: CSD Version 1.0
Data Read Access Time 1 (TAAC):
Data Read Access Time 2 (NSAC): 0
Max Data Transfer Rate:
Card Command Classes: 000000000000
Max Read Data Block Length: 0
Partial Blocks For Read Allowed: False
Write Block Misalignment: False
Read Block Misalignment: False
DSR Implemented: False
Device Size: 0
Max Read Current @ VDD Min: 0.5mA
Max Read Current @ VDD Max: 1mA
Max Write Current @ VDD Min: 0.5mA
Max Write Current @ VDD Max: 1mA
Device Size Multiplier: 2
Erase Single Block Enable: False
Erase Sector Size: 1
Write Protect Group Size: 1
Write Protect Group Enable: False
Write Speed Factor: 1
Max Write Data Block Length: 2^0
Partial Blocks For Write Allowed: False
File Format Group: False
Copy Flag (OTP): False
Permanent Write Protection: False
Temporary Write Protection: False
File Format: 0