Subversion Repositories pentevo

Rev

Rev 796 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include <io.h>
  4.  
  5. #include "emul.h"
  6. #include "vars.h"
  7. #include "sdcard.h"
  8.  
  9. #include "util.h"
  10.  
  11. void TSdCard::Reset()
  12. {
  13. //    printf(__FUNCTION__"\n");
  14.  
  15.     CurrState = ST_IDLE;
  16.     ArgCnt = 0;
  17.     Cmd = CMD_INVALID;
  18.     DataBlockLen = 512;
  19.     DataCnt = 0;
  20.  
  21.     CsdCnt = 0;
  22.     Csd[0] = (1 << 6); // CSD structure (SDHC)
  23.     Csd[1] = 0xE;  // TACC
  24.     Csd[2] = 0x00; // NSAC
  25.     Csd[3] = 0x32; // TRAN_SPEED
  26.     Csd[4] = 0x5B; // CCC x1x11011
  27.     Csd[5] = 0x59; // CCC 0101 | READ_BL_LEN 9
  28.     Csd[6] = 0x00; // READ_BL_PARTIAL | WRITE_BLK_MISALIGN | READ_BLK_MISALIGN | DSR_IMP
  29.  
  30.     UpdateCsdImageSize();
  31.  
  32.     Csd[10] = (1 << 6) | (0x3F << 1); // ERASE_BLK_EN | SECTOR_SIZE
  33.     Csd[11] = (1 << 7); // SECTOR_SIZE | WP_GRP_SIZE
  34.     Csd[12] = (2 << 2) | 2; // R2W_FACTOR | WRITE_BL_LEN 9
  35.     Csd[13] = (1 << 6); // WRITE_BL_LEN 9 | WRITE_BL_PARTIAL
  36.     Csd[14] = 0x00; // FILE_FORMAT_GRP | COPY | PERM_WRITE_PROTECT | TMP_WRITE_PROTECT | FILE_FORMAT
  37.     Csd[15] = 1; // CRC | 1
  38.  
  39.     CidCnt = 0;
  40.     memset(Cid, 0, sizeof(Cid));
  41.  
  42.     // OEM/Application ID (OID)
  43.     Cid[1] = 'U';
  44.     Cid[2] = 'S';
  45.  
  46.     // Product Name (PNM)
  47.     Cid[3] = 'U';
  48.     Cid[4] = 'S';
  49.     Cid[5] = '0' + (VER_HL / 10) % 10;
  50.     Cid[6] = '0' + VER_HL % 10;
  51.     Cid[7] = '0' + VER_A % 10;
  52.  
  53.     Cid[8] = 0x10; // Product Revision (PRV) (BCD)
  54.     Cid[14] = 0x04; // Manufacture Date Code (MDT)
  55.     Cid[15] = 1; // CRC7 | 1
  56.  
  57.     Ocr = 0x80200000;
  58.     OcrCnt = 0;
  59.     AppCmd = false;
  60. }
  61.  
  62. void TSdCard::UpdateCsdImageSize()
  63. {
  64.     Csd[7] = (ImageSize >> 16) & 0x3F; // C_SIZE
  65.     Csd[8] = (ImageSize >> 8) & 0xFF; // C_SIZE
  66.     Csd[9] = ImageSize & 0xFF; // C_SIZE
  67. }
  68.  
  69. void TSdCard::Wr(u8 Val)
  70. {
  71.     static u32 WrPos = -1U;
  72.     TState NextState = ST_IDLE;
  73. //    printf(__FUNCTION__" Val = %X\n", Val);
  74.  
  75.     if(!Image)
  76.         return;
  77.  
  78.     switch(CurrState)
  79.     {
  80.         case ST_IDLE:
  81.         case ST_WR_DATA_SIG:
  82.         {
  83.             if((Val & 0xC0) != 0x40) // start=0, transm=1
  84.                break;
  85.  
  86.             Cmd = TCmd(Val & 0x3F);
  87.             if(!AppCmd)
  88.             {
  89.                 switch(Cmd) // Check commands
  90.                 {
  91.                 case CMD_GO_IDLE_STATE:
  92. //                    printf(__FUNCTION__" CMD_GO_IDLE_STATE, Val = %X\n", Val);
  93.                     NextState = ST_RD_ARG;
  94.                     ArgCnt = 0;
  95.                 break;
  96.  
  97.                 case CMD_SEND_OP_COND:
  98. //                    printf(__FUNCTION__" CMD_SEND_OP_COND, Val = %X\n", Val);
  99.                     NextState = ST_RD_ARG;
  100.                     ArgCnt = 0;
  101.                 break;
  102.  
  103.                 case CMD_SET_BLOCKLEN:
  104. //                    printf(__FUNCTION__" CMD_SET_BLOCKLEN, Val = %X\n", Val);
  105.                     NextState = ST_RD_ARG;
  106.                     ArgCnt = 0;
  107.                 break;
  108.  
  109.                 case CMD_READ_SINGLE_BLOCK:
  110. //                    printf(__FUNCTION__" CMD_READ_SINGLE_BLOCK, Val = %X\n", Val);
  111.                     NextState = ST_RD_ARG;
  112.                     ArgCnt = 0;
  113.                 break;
  114.  
  115.                 case CMD_READ_MULTIPLE_BLOCK:
  116. //                    printf(__FUNCTION__" CMD_READ_MULTIPLE_BLOCK, Val = %X\n", Val);
  117.                     NextState = ST_RD_ARG;
  118.                     ArgCnt = 0;
  119.                 break;
  120.  
  121.                 case CMD_WRITE_BLOCK:
  122. //                    printf(__FUNCTION__" CMD_WRITE_BLOCK, Val = %X\n", Val);
  123.                     NextState = ST_RD_ARG;
  124.                     ArgCnt = 0;
  125.                 break;
  126.  
  127.                 case CMD_WRITE_MULTIPLE_BLOCK:
  128. //                    printf(__FUNCTION__" CMD_WRITE_MULTIPLE_BLOCK, Val = %X\n", Val);
  129.                     NextState = ST_RD_ARG;
  130.                     ArgCnt = 0;
  131.                 break;
  132.  
  133.                 case CMD_STOP_TRANSMISSION:
  134. //                    printf(__FUNCTION__" CMD_STOP_TRANSMISSION, Val = %X\n", Val);
  135.                     NextState = ST_RD_ARG;
  136.                     ArgCnt = 0;
  137.                 break;
  138.  
  139.                 case CMD_SEND_IF_COND:
  140. //                    printf(__FUNCTION__" CMD_SEND_IF_COND, Val = %X\n", Val);
  141.                     NextState = ST_RD_ARG;
  142.                     ArgCnt = 0;
  143.                 break;
  144.  
  145.                 case CMD_SEND_CSD:
  146. //                    printf(__FUNCTION__" CMD_SEND_CSD, Val = %X\n", Val);
  147.                     NextState = ST_RD_ARG;
  148.                     ArgCnt = 0;
  149.                     CsdCnt = 0;
  150.                 break;
  151.  
  152.                 case CMD_SEND_CID:
  153. //                    printf(__FUNCTION__" CMD_SEND_CID, Val = %X\n", Val);
  154.                     NextState = ST_RD_ARG;
  155.                     ArgCnt = 0;
  156.                     CidCnt = 0;
  157.                 break;
  158.  
  159.                 case CMD_CRC_ON_OFF:
  160. //                    printf(__FUNCTION__" CMD_CRC_ON_OFF, Val = %X\n", Val);
  161.                     NextState = ST_RD_ARG;
  162.                     ArgCnt = 0;
  163.                 break;
  164.  
  165.                 case CMD_READ_OCR:
  166. //                    printf(__FUNCTION__" CMD_READ_OCR, Val = %X\n", Val);
  167. //                    __debugbreak();
  168.                     NextState = ST_RD_ARG;
  169.                     ArgCnt = 0;
  170.                     OcrCnt = 0;
  171.                 break;
  172.  
  173.                 case CMD_APP_CMD:
  174. //                    printf(__FUNCTION__" CMD_APP_CMD, Val = %X\n", Val);
  175.                     NextState = ST_RD_ARG;
  176.                     ArgCnt = 0;
  177.                 break;
  178.  
  179.                 default:
  180.                     printf("%s Unknown CMD = 0x%X, Val = %X\n", __FUNCTION__, Cmd, Val);
  181.                     NextState = ST_RD_ARG;
  182.                     ArgCnt = 0;
  183.                 }
  184.             }
  185.             else // AppCmd
  186.             {
  187.                 switch(Cmd)
  188.                 {
  189.                 case CMD_SET_WR_BLK_ERASE_COUNT:
  190.                 case CMD_SD_SEND_OP_COND:
  191. //                    printf(__FUNCTION__" CMD_SD_SEND_OP_COND, Val = %X\n", Val);
  192.                     NextState = ST_RD_ARG;
  193.                     ArgCnt = 0;
  194.                 break;
  195.  
  196.                 default:
  197.                     printf("%s Unknown ACMD = 0x%X, Val = %X\n", __FUNCTION__, Cmd, Val);
  198.                     AppCmd = false;
  199.                 }
  200.             }
  201.         }
  202.         break;
  203.  
  204.         case ST_RD_ARG:
  205.             NextState = ST_RD_ARG;
  206.             ArgArr[3 - ArgCnt++] = Val;
  207.  
  208. //            printf(__FUNCTION__" ST_RD_ARG val=0x%X\n", Val);
  209.             if(ArgCnt == 4)
  210.             {
  211.                 if(!AppCmd)
  212.                 {
  213.                     switch(Cmd)
  214.                     {
  215.                     case CMD_READ_SINGLE_BLOCK:
  216. //                        printf(__FUNCTION__" CMD_READ_SINGLE_BLOCK, Addr = 0x%X\n", Arg);
  217.                         fseek(Image, long(Arg), SEEK_SET);
  218.                         fread(Buf, 512, 1, Image);
  219.                     break;
  220.  
  221.                     case CMD_READ_MULTIPLE_BLOCK:
  222. //                        printf(__FUNCTION__" CMD_READ_MULTIPLE_BLOCK, Addr = 0x%X\n", Arg);
  223.                         fseek(Image, long(Arg), SEEK_SET);
  224.                         fread(Buf, 512, 1, Image);
  225.                     break;
  226.  
  227.                     case CMD_WRITE_BLOCK:
  228. //                        printf(__FUNCTION__" CMD_WRITE_BLOCK, Addr = 0x%X\n", Arg);
  229.                     break;
  230.  
  231.                     case CMD_WRITE_MULTIPLE_BLOCK:
  232.                         WrPos = Arg;
  233. //                        printf(__FUNCTION__" CMD_WRITE_MULTIPLE_BLOCK, Addr = 0x%X\n", Arg);
  234.                     break;
  235.                     }
  236.                 }
  237.  
  238.                 NextState = ST_RD_CRC;
  239.                 ArgCnt = 0;
  240.             }
  241.         break;
  242.  
  243.         case ST_RD_CRC:
  244. //            printf(__FUNCTION__" ST_RD_CRC val=0x%X\n", Val);
  245.             NextState = GetRespondType();
  246.         break;
  247.  
  248.         case ST_RD_DATA_SIG:
  249.             NextState = ST_RD_DATA;
  250. /*
  251.             if(Val != 0xFE) // ╧ЁютхЁър ёшуэрЄєЁ√ фрээ√ї
  252.                 __debugbreak();
  253. */
  254.             DataCnt = 0;
  255.         break;
  256.  
  257.         case ST_RD_DATA_SIG_MUL:
  258.             switch(Val)
  259.             {
  260.             case 0xFC: // ╧ЁютхЁър ёшуэрЄєЁ√ фрээ√ї
  261. //                printf(__FUNCTION__" ST_RD_DATA_SIG_MUL, Start\n");
  262.                 DataCnt = 0;
  263.                 NextState = ST_RD_DATA_MUL;
  264.             break;
  265.             case 0xFD: // ╬ъюэўрэшх яхЁхфрўш
  266. //                printf(__FUNCTION__" ST_RD_DATA_SIG_MUL, Stop\n");
  267.                 NextState = ST_IDLE;
  268.             break;
  269.             default:
  270.                 NextState = ST_RD_DATA_SIG_MUL;
  271.             }
  272.         break;
  273.  
  274.         case ST_RD_DATA: // ╧Ёшхь фрээ√ї т сєЇхЁ
  275.         {
  276. //            printf(__FUNCTION__" ST_RD_DATA, Addr = 0x%X, Idx=%d\n", Arg, DataCnt);
  277.             Buf[DataCnt++] = Val;
  278.             NextState = ST_RD_DATA;
  279.             if(DataCnt == DataBlockLen) // ╟ряшё№ фрээ√ї т SD ърЁЄє
  280.             {
  281.                 DataCnt = 0;
  282. //                printf(__FUNCTION__" ST_RD_DATA, Addr = 0x%X, write to disk\n", Arg);
  283.                 fseek(Image, long(Arg), SEEK_SET);
  284.                 fwrite(Buf, 512, 1, Image);
  285.                 NextState = ST_RD_CRC16_1;
  286.             }
  287.         }
  288.         break;
  289.  
  290.         case ST_RD_DATA_MUL: // ╧Ёшхь фрээ√ї т сєЇхЁ
  291.         {
  292. //            printf(__FUNCTION__" ST_RD_DATA_MUL, Addr = 0x%X, Idx=%d\n", WrPos, DataCnt);
  293.             Buf[DataCnt++] = Val;
  294.             NextState = ST_RD_DATA_MUL;
  295.             if(DataCnt == DataBlockLen) // ╟ряшё№ фрээ√ї т SD ърЁЄє
  296.             {
  297.                 DataCnt = 0;
  298. //                printf(__FUNCTION__" ST_RD_DATA_MUL, Addr = 0x%X, write to disk\n", WrPos);
  299.                 fseek(Image, long(WrPos), SEEK_SET);
  300.                 fwrite(Buf, 512, 1, Image);
  301.                 WrPos += 512;
  302.                 NextState = ST_RD_CRC16_1;
  303.             }
  304.         }
  305.         break;
  306.  
  307.         case ST_RD_CRC16_1: // ╫Єхэшх ёЄрЁ°хую срщЄр CRC16
  308.             printf("%s CRC16_1=0x%X\n", __FUNCTION__, Val);
  309.             NextState = ST_RD_CRC16_2;
  310.         break;
  311.  
  312.         case ST_RD_CRC16_2: // ╫Єхэшх ьырф°хую срщЄр CRC16
  313.             printf("%s CRC16_2=0x%X\n", __FUNCTION__, Val);
  314.             NextState = ST_WR_DATA_RESP;
  315.         break;
  316.  
  317.         default:
  318.             printf("%s Unknown St = 0x%X, Val = 0x%X\n", __FUNCTION__, CurrState, Val);
  319.             return;
  320.     }
  321.  
  322.     CurrState = NextState;
  323. }
  324.  
  325. u8 TSdCard::Rd()
  326. {
  327. //    printf(__FUNCTION__" cmd=0x%X, St=0x%X\n", Cmd, CurrState);
  328.     if(!Image)
  329.         return 0xFF;
  330.  
  331.     switch(Cmd)
  332.     {
  333.     case CMD_GO_IDLE_STATE:
  334.         if(CurrState == ST_R1)
  335.         {
  336. //            Cmd = CMD_INVALID;
  337.             CurrState = ST_IDLE;
  338.             return 1;
  339.         }
  340.     break;
  341.     case CMD_SEND_OP_COND:
  342.         if(CurrState == ST_R1)
  343.         {
  344. //            Cmd = CMD_INVALID;
  345.             CurrState = ST_IDLE;
  346.             return 0;
  347.         }
  348.     break;
  349.     case CMD_SET_BLOCKLEN:
  350.         if(CurrState == ST_R1)
  351.         {
  352. //            Cmd = CMD_INVALID;
  353.             CurrState = ST_IDLE;
  354.             return 0;
  355.         }
  356.     break;
  357.     case CMD_SEND_IF_COND:
  358.         if(CurrState == ST_R7)
  359.         {
  360.             CurrState = ST_IDLE;
  361.             return 5; // invalid command | idle state
  362.         }
  363.     break;
  364.  
  365.     case CMD_READ_OCR:
  366.         if(CurrState == ST_R1)
  367.         {
  368.             CurrState = ST_R3;
  369.             return 0;
  370.         }
  371.     break;
  372.  
  373.     case CMD_APP_CMD:
  374.         if(CurrState == ST_R1)
  375.         {
  376.             CurrState = ST_IDLE;
  377.             return 0;
  378.         }
  379.     break;
  380.  
  381.     case CMD_SET_WR_BLK_ERASE_COUNT:
  382.         if(CurrState == ST_R1)
  383.         {
  384.             CurrState = ST_IDLE;
  385.             return 0;
  386.         }
  387.     break;
  388.  
  389.     case CMD_SD_SEND_OP_COND:
  390.         if(CurrState == ST_R1)
  391.         {
  392.             CurrState = ST_IDLE;
  393.             return 0;
  394.         }
  395.     break;
  396.  
  397.     case CMD_CRC_ON_OFF:
  398.         if(CurrState == ST_R1)
  399.         {
  400.             CurrState = ST_IDLE;
  401.             return 0;
  402.         }
  403.     break;
  404.  
  405.     case CMD_STOP_TRANSMISSION:
  406.         switch(CurrState)
  407.         {
  408.         case ST_R1:
  409.             CurrState = ST_R1b;
  410.             return 0;
  411.         case ST_R1b:
  412.             CurrState = ST_IDLE;
  413.             return 0xFF;
  414.         }
  415.     break;
  416.  
  417.     case CMD_READ_SINGLE_BLOCK:
  418.         switch(CurrState)
  419.         {
  420.         case ST_R1: // ╬ЄтхЄ эр ъюьрэфє (ърЁЄр->їюёЄ)
  421.             CurrState = ST_WR_DATA_SIG;
  422.             return 0;
  423.         case ST_WR_DATA_SIG: // ╥юъхэ фрээ√ї (ърЁЄр->їюёЄ)
  424.             DataCnt = 0;
  425.             CurrState = ST_WR_DATA;
  426.             return 0xFE;
  427.         case ST_WR_DATA: // ╧хЁхфрўр фрээ√ї (ърЁЄр->їюёЄ)
  428.         {
  429.             u8 Val = Buf[DataCnt++];
  430.             if(DataCnt == DataBlockLen)
  431.             {
  432.                 DataCnt = 0;
  433.                 CurrState = ST_WR_CRC16_1;
  434.             }
  435.             return Val;
  436.         }
  437.         case ST_WR_CRC16_1: // ╧хЁхфрўр crc16 (ърЁЄр->їюёЄ)
  438.             CurrState = ST_WR_CRC16_2;
  439.             return 0xFF;
  440.         case ST_WR_CRC16_2: // ╧хЁхфрўр crc16 (ърЁЄр->їюёЄ)
  441.             CurrState = ST_IDLE;
  442.             Cmd = CMD_INVALID;
  443.             return 0xFF;
  444.         }
  445. //        Cmd = CMD_INVALID;
  446.     break;
  447.  
  448.     case CMD_READ_MULTIPLE_BLOCK:
  449.         switch(CurrState)
  450.         {
  451.         case ST_R1: // ╬ЄтхЄ эр ъюьрэфє (ърЁЄр->їюёЄ)
  452.             CurrState = ST_WR_DATA_SIG;
  453.             return 0;
  454.         case ST_WR_DATA_SIG: // ╥юъхэ фрээ√ї (ърЁЄр->їюёЄ)
  455.             DataCnt = 0;
  456.             CurrState = ST_IDLE;
  457.             return 0xFE;
  458.         case ST_IDLE: // ╧хЁхфрўр фрээ√ї (ърЁЄр->їюёЄ), яЁхЁ√трхЄё  ъюьрэфющ CMD_STOP_TRANSMISSION
  459.         {
  460.             u8 Val = Buf[DataCnt++];
  461.             if(DataCnt == DataBlockLen)
  462.             {
  463.                 DataCnt = 0;
  464.                 fread(Buf, 512, 1, Image);
  465.                 CurrState = ST_WR_CRC16_1;
  466.             }
  467.             return Val;
  468.         }
  469.         case ST_WR_CRC16_1: // ╧хЁхфрўр crc16 (ърЁЄр->їюёЄ)
  470.             CurrState = ST_WR_CRC16_2;
  471.             return 0xFF;
  472.         case ST_WR_CRC16_2: // ╧хЁхфрўр crc16 (ърЁЄр->їюёЄ)
  473.             CurrState = ST_WR_DATA_SIG;
  474.             return 0xFF;
  475.         }
  476.     break;
  477.  
  478.     case CMD_SEND_CSD:
  479.         switch(CurrState)
  480.         {
  481.         case ST_R1:
  482.             CurrState = ST_WR_DATA_SIG;
  483.             return 0;
  484.         case ST_WR_DATA_SIG:
  485.             CurrState = ST_WR_DATA;
  486.             return 0xFE;
  487.         case ST_WR_DATA:
  488.         {
  489.             u8 Val = Csd[CsdCnt++];
  490.             if(CsdCnt == 16)
  491.             {
  492.                 CsdCnt = 0;
  493.                 CurrState = ST_IDLE;
  494.                 Cmd = CMD_INVALID;
  495.             }
  496.             return Val;
  497.         }
  498.         }
  499. //        Cmd = CMD_INVALID;
  500.     break;
  501.  
  502.     case CMD_SEND_CID:
  503.         switch(CurrState)
  504.         {
  505.         case ST_R1:
  506.             CurrState = ST_WR_DATA_SIG;
  507.             return 0x00;
  508.         case ST_WR_DATA_SIG:
  509.             CurrState = ST_WR_DATA;
  510.             return 0xFE;
  511.         case ST_WR_DATA:
  512.         {
  513.             u8 Val = Cid[CidCnt++];
  514.             if(CidCnt == 16)
  515.             {
  516.                 CidCnt = 0;
  517.                 CurrState = ST_IDLE;
  518.                 Cmd = CMD_INVALID;
  519.             }
  520.             return Val;
  521.         }
  522.         }
  523. //        Cmd = CMD_INVALID;
  524.     break;
  525.  
  526.     case CMD_WRITE_BLOCK:
  527. //        printf(__FUNCTION__" cmd=0x%X, St=0x%X\n", Cmd, CurrState);
  528.         switch(CurrState)
  529.         {
  530.         case ST_R1:
  531.             CurrState = ST_RD_DATA_SIG;
  532.             return 0;
  533.  
  534.         case ST_WR_DATA_RESP:
  535.         {
  536.             CurrState = ST_IDLE;
  537.             u8 Resp = ((STAT_DATA_ACCEPTED) << 1) | 1;
  538.             return Resp;
  539.         }
  540.         }
  541.     break;
  542.  
  543.     case CMD_WRITE_MULTIPLE_BLOCK:
  544.         switch(CurrState)
  545.         {
  546.         case ST_R1:
  547.             CurrState = ST_RD_DATA_SIG_MUL;
  548.             return 0;
  549.         case ST_WR_DATA_RESP:
  550.         {
  551.             CurrState = ST_RD_DATA_SIG_MUL;
  552.             u8 Resp = ((STAT_DATA_ACCEPTED) << 1) | 1;
  553.             return Resp;
  554.         }
  555.         }
  556.     break;
  557.  
  558.     default:
  559.         if(!((CurrState == ST_IDLE) && (Cmd == CMD_INVALID)))
  560.         {
  561.             printf("%s Unknown CMD = 0x%X\n", __FUNCTION__, Cmd);
  562.         }
  563.  
  564.         if(Cmd != CMD_INVALID)
  565.         {
  566.             return 4; // illegal command
  567.         }
  568.     }
  569.  
  570.     if(CurrState == ST_R3)
  571.     {
  572.         u8 Val = OcrArr[3 - OcrCnt++];
  573.  
  574.         if(OcrCnt == 4)
  575.         {
  576.             CurrState = ST_IDLE;
  577.             OcrCnt = 0;
  578.         }
  579.         return Val;
  580.     }
  581.     return 0xFF;
  582. }
  583.  
  584. TSdCard::TState TSdCard::GetRespondType()
  585. {
  586.     if(!AppCmd)
  587.     {
  588.         switch(Cmd)
  589.         {
  590.         case CMD_APP_CMD:
  591.             AppCmd = true;
  592.         case CMD_GO_IDLE_STATE:
  593.         case CMD_SEND_OP_COND:
  594.         case CMD_SET_BLOCKLEN:
  595.         case CMD_READ_SINGLE_BLOCK:
  596.         case CMD_READ_MULTIPLE_BLOCK:
  597.         case CMD_CRC_ON_OFF:
  598.         case CMD_STOP_TRANSMISSION:
  599.         case CMD_SEND_CSD:
  600.         case CMD_SEND_CID:
  601.         case CMD_WRITE_BLOCK:
  602.         case CMD_WRITE_MULTIPLE_BLOCK:
  603.             return ST_R1;
  604.         case CMD_READ_OCR:
  605.             return ST_R1; // R3
  606.         case CMD_SEND_IF_COND:
  607.             return ST_R7;
  608.         default:
  609.             printf("%s Unknown CMD = 0x%X\n", __FUNCTION__, Cmd);
  610.             return ST_R1;
  611.         }
  612.     }
  613.     else
  614.     {
  615.         AppCmd = false;
  616.         switch(Cmd)
  617.         {
  618.             case CMD_SET_WR_BLK_ERASE_COUNT:
  619.             case CMD_SD_SEND_OP_COND:
  620.                 AppCmd = false;
  621.                 return ST_R1;
  622.             default:
  623.                 printf("%s Unknown ACMD = 0x%X\n", __FUNCTION__, Cmd);
  624.         }
  625.     }
  626.  
  627.     return ST_IDLE;
  628. }
  629.  
  630. void TSdCard::Open(const char *Name)
  631. {
  632. //    printf(__FUNCTION__"\n");
  633.     assert(!Image);
  634.     Image = fopen(Name, "r+b");
  635.     if(!Image)
  636.     {
  637.         if(Name[0])
  638.         {
  639.             errmsg("can't find SD card image `%s'", Name);
  640.         }
  641.         return;
  642.     }
  643.     ImageSize = u32(_filelengthi64(fileno(Image)) / (512 * 1024)) - 1;
  644.     UpdateCsdImageSize();
  645. }
  646.  
  647. void TSdCard::Close()
  648. {
  649.     if(Image)
  650.     {
  651.         fclose(Image);
  652.         Image = nullptr;
  653.     }
  654. }
  655.  
  656. TSdCard SdCard;
  657.