none
problem on access SD memory card using DeviceIoControl

    Question

  • user-mode application could use DeviceIoControl() to send SD commands (cmd0, ... those defined in SD card physical specification) to SD memory card directly.

    (Of couse this memory card must be plugged into NoteBook computer directly instead of employing a card reader).

    For example, DeviceIoControl(hVol, IOCTL_SFFDISK_DEVICE_COMMAND, structure of SFFDISK_DEVICE_COMMAND_DATA, ...)

    Here comes the problem:

    In SFFDISK_DEVICE_COMMAND_DATA structure in sffdisk.h, one field "Command" of enumeration type SFFDISK_DCMD indicate "the kind of action" to be performed.

    This field could be

    SFFDISK_DC_GET_VERSION,
    SFFDISK_DC_LOCK_CHANNEL,
    SFFDISK_DC_UNLOCK_CHANNEL,
    SFFDISK_DC_DEVICE_COMMAND

    For the three former cases, DeviceIoControl() works correctly, but for the later one, it always fails with errorce 5 (access denied)

    This user-mode application is run under "Administrator" logon session.

    I tried to clear DACL of this SD card such that everyone has fully access to this memory card.

    But DeviceIoControl() still terminates with ERROR_ACCESS_DENIED.

    Accroding to MSDN cc500400,

    Handle to Logical and Physical disk drives might be different.  I tried both cases but DeviceIoControl() still does not function.

    Any one could help this ?

     

    Thursday, October 09, 2008 6:33 AM

All replies

  • Do You figure it out?

    I get same error 5 on this code:

     

     

    HANDLE hDevice= ::CreateFile(L"\\\\.\\G:", FILE_READ_ATTRIBUTES,

    FILE_SHARE_READ | FILE_SHARE_WRITE,

    NULL, OPEN_EXISTING, 0, NULL);

    ///SD command to SD device

    int nSizeOfCmd = sizeof (SFFDISK_DEVICE_COMMAND_DATA) + sizeof

    (SDCMD_DESCRIPTOR) + 6;

    SFFDISK_DEVICE_COMMAND_DATA *pCmdGoIdle = (SFFDISK_DEVICE_COMMAND_DATA

    *) new BYTE[nSizeOfCmd];

    //if (NULL == pCmdGoIdle)

    //{

    //return FALSE;

    //}

    memset(pCmdGoIdle, 0, nSizeOfCmd);

    pCmdGoIdle->HeaderSize = sizeof (SFFDISK_DEVICE_COMMAND_DATA);

    pCmdGoIdle->Command = SFFDISK_DC_DEVICE_COMMAND;

    pCmdGoIdle->ProtocolArgumentSize = sizeof (SDCMD_DESCRIPTOR);

    pCmdGoIdle->DeviceDataBufferSize = 20;

    ///Command protocol

    SDCMD_DESCRIPTOR stCmdDescriptor = { 0 };

    stCmdDescriptor.Cmd = SDCMD_IO_RW_DIRECT;

    stCmdDescriptor.CmdClass = SDCC_STANDARD;

    stCmdDescriptor.ResponseType = SDRT_NONE;

    stCmdDescriptor.TransferDirection = SDTD_WRITE;

    stCmdDescriptor.TransferType = SDTT_CMD_ONLY;

    memcpy((BYTE *)(&(pCmdGoIdle->Data[0])), &stCmdDescriptor,

    sizeof(SDCMD_DESCRIPTOR));

    ///Command data, SD command 0, GO_IDLE_STATE

    BYTE bySDCmdDevil = {0x42, 0x00,0x00,0x00,0x00,0x00};

    // BYTE bySDCmdDevil = {0x95, 0x00, 0x00, 0x00, 0x00, 0x40};

    memcpy(&(pCmdGoIdle->Data[0]) + sizeof (SDCMD_DESCRIPTOR), &bySDCmd,

    20);

    DWORD dwBytesReturned = 0;

    BOOL bResult = :Big SmileeviceIoControl(

    hDevice

    , IOCTL_SFFDISK_DEVICE_COMMAND

    , pCmdGoIdle

    , nSizeOfCmd

    , NULL

    , 0

    , &dwBytesReturned

    , NULL);

    ///For all the command we send, the return value of DeviceIoControl always return FALSE

    ///And the value of dwLastError always return 5 (Access is denied)

    DWORD dwLastError = GetLastError();

    ///How can I access the SD memory card and send the command to it?

    delete[] pCmdGoIdle;

    pCmdGoIdle = NULL;

    Friday, October 24, 2008 1:34 PM
  • We don't have any solution yet.

    Microsoft suggested us to sign a contract of 'Premier Support' with Microsoft to get the further support.

     

     

    Tuesday, October 28, 2008 1:49 AM
  • I've been talking to someone by email about this, and using bits of his code and bits of the code further up in this thread I think I've managed to get cmd10 to go, and received the CID back.


            int nSizeOfCmd = sizeof (SFFDISK_DEVICE_COMMAND_DATA) + sizeof(SDCMD_DESCRIPTOR) + 16;
            SFFDISK_DEVICE_COMMAND_DATA *pCmd = (SFFDISK_DEVICE_COMMAND_DATA*) new BYTE[nSizeOfCmd];
            memset(pCmd, 0, nSizeOfCmd);       
            pCmd->HeaderSize = sizeof (SFFDISK_DEVICE_COMMAND_DATA);
            pCmd->Command = SFFDISK_DC_DEVICE_COMMAND;
            pCmd->ProtocolArgumentSize = sizeof (SDCMD_DESCRIPTOR);
            pCmd->DeviceDataBufferSize = 16;
            ULONG_PTR info = 0;
            pCmd->Information = info;

            ///Command protocol
            SDCMD_DESCRIPTOR sdCmdDescriptor = { 0 };
            sdCmdDescriptor.Cmd = 10; //SDCMD_IO_RW_DIRECT;
            sdCmdDescriptor.CmdClass = SDCC_STANDARD;
            sdCmdDescriptor.TransferDirection = SDTD_READ;
            sdCmdDescriptor.TransferType = SDTT_CMD_ONLY;
            sdCmdDescriptor.ResponseType = SDRT_2;       
            memcpy((BYTE *)(&(pCmd->Data[0])), &sdCmdDescriptor, sizeof(SDCMD_DESCRIPTOR));       

           
            // BYTE bySDCmdDevil = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95};
            // BYTE bySDCmdDevil = {0x95, 0x00, 0x00, 0x00, 0x00, 0x40}; // LSB MSB?
            // memcpy(&(pCmd->Data[0]) + sizeof (SDCMD_DESCRIPTOR), &bySDCmd, 6);

            DWORD dwBytesReturned = 0;
            BOOL bResult = DeviceIoControl(hVol, IOCTL_SFFDISK_DEVICE_COMMAND, pCmd, nSizeOfCmd, pCmd, nSizeOfCmd, &dwBytesReturned, NULL);       
           

    Note the big differences:
     - sdCmdDescriptor is set to the command number
     - I don't bother laying out the command as described in the sd documentation, the data sent is the
    SFFDISK_DEVICE_COMMAND_DATA followed by the SDCMD_DESCRIPTOR followed by a blank blob of memory large enough for the return. In CMD10's case this is an R2 response, so 16 bytes.

    In Windows Device Manager I can see the hardware ID of my SD Card:

    SD\VID_1d&OID_4144&PID_SD&REV_1.0


    Which can be translated using the WDK documentation "Identifiers for Secure Digital (SD) Devices)"
    http://msdn.microsoft.com/en-us/library/ms791077.aspx

    And we can look up the CID in the "Simplified Physical Layer Spec" (p75)
    http://www.sdcard.org/developers/tech/sdcard/

    MID is 0x1d = 29
    OID is 0x4144 = 65, 68
    PID is "SD" = 83, 68  (Actually it is "SD   ", 83, 68, 32, 32, 32)
    REV is 10000b = 0x10 = 16

    I got back these bytes:

    138, 0, 162, 6, 0, 0, 16, 32, 32, 32, 68, 83, 68, 65, 29, 0

    It's reversed and slightly off - there should be a byte to the left of 138 and the 0 on the end is not part of the CID.

    0 - oops
    29 MID
    65 OID
    68 OID
    83 PNM
    68 PNM
    32 PNM
    32 PNM
    32 PNM
    16 PRV
    0  PSN
    0  PSN
    6  PSN
    162 PSN
    0   reserved 4 bits, MDT 4 bits
    138 MDT
    ??? CRC















    Sunday, November 23, 2008 2:19 PM
  • Dear,

     

      Thanks for your information.

      For Cmd 10, it could function well.

     

      Nevertheless the original problem seem not be resolved.

      Bits of code were change for Cmd 0

      ///Command protocol
      sdCmdDescriptor.Cmd = 0; //SDCMD_IO_RW_DIRECT;
      sdCmdDescriptor.ResponseType = SDRT_NONE;

     

       ERROR_ACCESS_DENIED was returned from DeviceIoControl(...)

     

       Could you help this?

     


     

     

     

    Tuesday, November 25, 2008 5:14 AM
  • Actually, I tried to access "protected area" in SD memory card.

    To retrieve media ID (ACMD 44), key block (ACMD 43) and etc, CMD 0, ACMD 41, CMD 2, CMD 3 and CMD 7 must be sent to SD card first.  Nevertheless DeviceIoControl(...) return 0x05 for those ones.  Could you provide some suggestion to this?

     

    Tuesday, November 25, 2008 6:10 AM
  • My createfile options are different:

    CreateFile(path, GenericRead Or GenericWrite, FileShareRead Or FileShareWrite, _
                                            IntPtr.Zero, OpenExisting, 0, IntPtr.Zero)

    path can be:  \\.\PhysicalDrive1 or \\.\C: style

    It fails with error 5 without GenericWrite.
    Friday, November 28, 2008 4:27 AM
  • Also note problems with the IOCTL on Vista:

    http://support.microsoft.com/kb/944240
    Friday, November 28, 2008 9:18 AM
  • Hi !jo0ls. I want to get sd card CID information under windows xp . I read your reply, but I send CMD10 command returns false. I need code sample to get SD Card CID. Please help me. Thanks!
    Wednesday, July 17, 2013 8:06 AM
  • Hi,

    I am a beginner to device driver programming in windows. I am trying to send sd commands to sd card and emmc(inand) to perform a single block write. CMD 24 is single block write in both (sd/emmc) specs. I am using SFFDISK_DEVICE_COMMAND_DATA and SDCMD_DESCRIPTOR structure, first i was getting error code 5 access denied, than from some where in the blog i saw to dismount and lock the volume before writing to drive, now i am getting error code 50 request not supported. Have put my code below please advise where i am going wrong

    #include "stdafx.h"
    #include <stdio.h>
    #include <windows.h>
    #include <cstring>
    #include "km\sddef.h"
    #include "km\sffdisk.h"

    int main()
    {
    wchar_t dev_path[20] = L"\\\\.\\E:";
    HANDLE hDevice;               // handle to the drive to be examined
    BOOL bResult=FALSE;                 // results flag
    BYTE inputData[512] = { 0 };
    int nSizeofCmd = 0;
    DWORD dwBytesReturned = 0;

    hDevice = CreateFile((LPCWSTR)dev_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
    printf("CreateFile() failed!\n");
    return (FALSE);
    }
    SFFDISK_DEVICE_COMMAND_DATA* commandData=NULL;
    nSizeofCmd = sizeof (SFFDISK_DEVICE_COMMAND_DATA)+sizeof(SDCMD_DESCRIPTOR)+512;
    commandData = (SFFDISK_DEVICE_COMMAND_DATA*) new BYTE[nSizeofCmd];
    memset(commandData, 0, nSizeofCmd);
    //std::memset(commandData, 0, sizeof(commandData));
    commandData->HeaderSize = sizeof(SFFDISK_DEVICE_COMMAND_DATA);
    commandData->Command = SFFDISK_DC_DEVICE_COMMAND;
    commandData->ProtocolArgumentSize = sizeof(SDCMD_DESCRIPTOR);
    commandData->Information = 100;
    commandData->DeviceDataBufferSize = 512;

    SDCMD_DESCRIPTOR commandDescriptor;
    std::memset(&commandDescriptor, 0, sizeof(commandDescriptor));
    commandDescriptor.Cmd = 24;   // <--- Not what the documentation indicates!
    commandDescriptor.CmdClass = SDCC_STANDARD;
    commandDescriptor.TransferDirection = SDTD_WRITE;
    commandDescriptor.TransferType = SDTT_SINGLE_BLOCK;
    commandDescriptor.ResponseType = SDRT_1;

    memset(inputData, 0, sizeof(inputData));

    memcpy((BYTE *)(&(commandData->Data[0])), &commandDescriptor, sizeof(SDCMD_DESCRIPTOR));
    memcpy((BYTE *)(&(commandData->Data[0]) + sizeof (SDCMD_DESCRIPTOR)), &inputData, sizeof(inputData));
    dwBytesReturned = 0;
    bResult = DeviceIoControl(hDevice, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &dwBytesReturned, 0);

    if (bResult)

    {

    bResult = DeviceIoControl(hDevice, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dwBytesReturned, 0);

    }
    bResult = 0;
    bResult = DeviceIoControl(hDevice, IOCTL_SFFDISK_DEVICE_COMMAND, commandData, nSizeofCmd, commandData, nSizeofCmd, &dwBytesReturned, NULL);
    if (bResult == 0)
    {
    int result = GetLastError();
    printf("%d\n", result);
    }
    else
    {
    printf("success");
    }

    // Free Memory 
    free(commandData);
    CloseHandle(hDevice);

    return 0;
    }

    Thanks,

    Kamlendra chandra

    Thursday, December 11, 2014 10:10 AM