Top secrets sources NedoPC pentevo

Rev

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

#include "std.h"

#include <io.h>

#include "emul.h"
#include "vars.h"
#include "sdcard.h"

#include "util.h"

void TSdCard::Reset()
{
//    printf(__FUNCTION__"\n");

    CurrState = ST_IDLE;
    ArgCnt = 0;
    Cmd = CMD_INVALID;
    DataBlockLen = 512;
    DataCnt = 0;

    CsdCnt = 0;
    Csd[0] = (1 << 6); // CSD structure (SDHC)
    Csd[1] = 0xE;  // TACC
    Csd[2] = 0x00; // NSAC
    Csd[3] = 0x32; // TRAN_SPEED
    Csd[4] = 0x5B; // CCC x1x11011
    Csd[5] = 0x59; // CCC 0101 | READ_BL_LEN 9
    Csd[6] = 0x00; // READ_BL_PARTIAL | WRITE_BLK_MISALIGN | READ_BLK_MISALIGN | DSR_IMP

    UpdateCsdImageSize();

    Csd[10] = (1 << 6) | (0x3F << 1); // ERASE_BLK_EN | SECTOR_SIZE
    Csd[11] = (1 << 7); // SECTOR_SIZE | WP_GRP_SIZE
    Csd[12] = (2 << 2) | 2; // R2W_FACTOR | WRITE_BL_LEN 9
    Csd[13] = (1 << 6); // WRITE_BL_LEN 9 | WRITE_BL_PARTIAL
    Csd[14] = 0x00; // FILE_FORMAT_GRP | COPY | PERM_WRITE_PROTECT | TMP_WRITE_PROTECT | FILE_FORMAT
    Csd[15] = 1; // CRC | 1

    CidCnt = 0;
    memset(Cid, 0, sizeof(Cid));

    // OEM/Application ID (OID)
    Cid[1] = 'U';
    Cid[2] = 'S';

    // Product Name (PNM)
    Cid[3] = 'U';
    Cid[4] = 'S';
    Cid[5] = '0' + (VER_HL / 10) % 10;
    Cid[6] = '0' + VER_HL % 10;
    Cid[7] = '0' + VER_A % 10;

    Cid[8] = 0x10; // Product Revision (PRV) (BCD)
    Cid[14] = 0x04; // Manufacture Date Code (MDT)
    Cid[15] = 1; // CRC7 | 1

    Ocr = 0x80200000;
    OcrCnt = 0;
    AppCmd = false;
}

void TSdCard::UpdateCsdImageSize()
{
    Csd[7] = (ImageSize >> 16) & 0x3F; // C_SIZE
    Csd[8] = (ImageSize >> 8) & 0xFF; // C_SIZE
    Csd[9] = ImageSize & 0xFF; // C_SIZE
}

void TSdCard::Wr(u8 Val)
{
    static u32 WrPos = -1U;
    TState NextState = ST_IDLE;
//    printf(__FUNCTION__" Val = %X\n", Val);

    if(!Image)
        return;

    switch(CurrState)
    {
        case ST_IDLE:
        case ST_WR_DATA_SIG:
        {
            if((Val & 0xC0) != 0x40) // start=0, transm=1
               break;

            Cmd = TCmd(Val & 0x3F);
            if(!AppCmd)
            {
                switch(Cmd) // Check commands
                {
                case CMD_GO_IDLE_STATE:
//                    printf(__FUNCTION__" CMD_GO_IDLE_STATE, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_SEND_OP_COND:
//                    printf(__FUNCTION__" CMD_SEND_OP_COND, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_SET_BLOCKLEN:
//                    printf(__FUNCTION__" CMD_SET_BLOCKLEN, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_READ_SINGLE_BLOCK:
//                    printf(__FUNCTION__" CMD_READ_SINGLE_BLOCK, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_READ_MULTIPLE_BLOCK:
//                    printf(__FUNCTION__" CMD_READ_MULTIPLE_BLOCK, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_WRITE_BLOCK:
//                    printf(__FUNCTION__" CMD_WRITE_BLOCK, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_WRITE_MULTIPLE_BLOCK:
//                    printf(__FUNCTION__" CMD_WRITE_MULTIPLE_BLOCK, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_STOP_TRANSMISSION:
//                    printf(__FUNCTION__" CMD_STOP_TRANSMISSION, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_SEND_IF_COND:
//                    printf(__FUNCTION__" CMD_SEND_IF_COND, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_SEND_CSD:
//                    printf(__FUNCTION__" CMD_SEND_CSD, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                    CsdCnt = 0;
                break;

                case CMD_SEND_CID:
//                    printf(__FUNCTION__" CMD_SEND_CID, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                    CidCnt = 0;
                break;

                case CMD_CRC_ON_OFF:
//                    printf(__FUNCTION__" CMD_CRC_ON_OFF, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                case CMD_READ_OCR:
//                    printf(__FUNCTION__" CMD_READ_OCR, Val = %X\n", Val);
//                    __debugbreak();
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                    OcrCnt = 0;
                break;

                case CMD_APP_CMD:
//                    printf(__FUNCTION__" CMD_APP_CMD, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                default:
                    printf("%s Unknown CMD = 0x%X, Val = %X\n", __FUNCTION__, Cmd, Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                }
            }
            else // AppCmd
            {
                switch(Cmd)
                {
                case CMD_SET_WR_BLK_ERASE_COUNT:
                case CMD_SD_SEND_OP_COND:
//                    printf(__FUNCTION__" CMD_SD_SEND_OP_COND, Val = %X\n", Val);
                    NextState = ST_RD_ARG;
                    ArgCnt = 0;
                break;

                default:
                    printf("%s Unknown ACMD = 0x%X, Val = %X\n", __FUNCTION__, Cmd, Val);
                    AppCmd = false;
                }
            }
        }
        break;

        case ST_RD_ARG:
            NextState = ST_RD_ARG;
            ArgArr[3 - ArgCnt++] = Val;

//            printf(__FUNCTION__" ST_RD_ARG val=0x%X\n", Val);
            if(ArgCnt == 4)
            {
                if(!AppCmd)
                {
                    switch(Cmd)
                    {
                    case CMD_READ_SINGLE_BLOCK:
//                        printf(__FUNCTION__" CMD_READ_SINGLE_BLOCK, Addr = 0x%X\n", Arg);
                        fseek(Image, long(Arg), SEEK_SET);
                        fread(Buf, 512, 1, Image);
                    break;

                    case CMD_READ_MULTIPLE_BLOCK:
//                        printf(__FUNCTION__" CMD_READ_MULTIPLE_BLOCK, Addr = 0x%X\n", Arg);
                        fseek(Image, long(Arg), SEEK_SET);
                        fread(Buf, 512, 1, Image);
                    break;

                    case CMD_WRITE_BLOCK:
//                        printf(__FUNCTION__" CMD_WRITE_BLOCK, Addr = 0x%X\n", Arg);
                    break;

                    case CMD_WRITE_MULTIPLE_BLOCK:
                        WrPos = Arg;
//                        printf(__FUNCTION__" CMD_WRITE_MULTIPLE_BLOCK, Addr = 0x%X\n", Arg);
                    break;
                    }
                }

                NextState = ST_RD_CRC;
                ArgCnt = 0;
            }
        break;

        case ST_RD_CRC:
//            printf(__FUNCTION__" ST_RD_CRC val=0x%X\n", Val);
            NextState = GetRespondType();
        break;

        case ST_RD_DATA_SIG:
            NextState = ST_RD_DATA;
/*
            if(Val != 0xFE) // Ïðîâåðêà ñèãíàòóðû äàííûõ
                __debugbreak();
*/

            DataCnt = 0;
        break;

        case ST_RD_DATA_SIG_MUL:
            switch(Val)
            {
            case 0xFC: // Ïðîâåðêà ñèãíàòóðû äàííûõ
//                printf(__FUNCTION__" ST_RD_DATA_SIG_MUL, Start\n");
                DataCnt = 0;
                NextState = ST_RD_DATA_MUL;
            break;
            case 0xFD: // Îêîí÷àíèå ïåðåäà÷è
//                printf(__FUNCTION__" ST_RD_DATA_SIG_MUL, Stop\n");
                NextState = ST_IDLE;
            break;
            default:
                NextState = ST_RD_DATA_SIG_MUL;
            }
        break;

        case ST_RD_DATA: // Ïðèåì äàííûõ â áóôåð
        {
//            printf(__FUNCTION__" ST_RD_DATA, Addr = 0x%X, Idx=%d\n", Arg, DataCnt);
            Buf[DataCnt++] = Val;
            NextState = ST_RD_DATA;
            if(DataCnt == DataBlockLen) // Çàïèñü äàííûõ â SD êàðòó
            {
                DataCnt = 0;
//                printf(__FUNCTION__" ST_RD_DATA, Addr = 0x%X, write to disk\n", Arg);
                fseek(Image, long(Arg), SEEK_SET);
                fwrite(Buf, 512, 1, Image);
                NextState = ST_RD_CRC16_1;
            }
        }
        break;

        case ST_RD_DATA_MUL: // Ïðèåì äàííûõ â áóôåð
        {
//            printf(__FUNCTION__" ST_RD_DATA_MUL, Addr = 0x%X, Idx=%d\n", WrPos, DataCnt);
            Buf[DataCnt++] = Val;
            NextState = ST_RD_DATA_MUL;
            if(DataCnt == DataBlockLen) // Çàïèñü äàííûõ â SD êàðòó
            {
                DataCnt = 0;
//                printf(__FUNCTION__" ST_RD_DATA_MUL, Addr = 0x%X, write to disk\n", WrPos);
                fseek(Image, long(WrPos), SEEK_SET);
                fwrite(Buf, 512, 1, Image);
                WrPos += 512;
                NextState = ST_RD_CRC16_1;
            }
        }
        break;

        case ST_RD_CRC16_1: // ×òåíèå ñòàðøåãî áàéòà CRC16
            printf("%s CRC16_1=0x%X\n", __FUNCTION__, Val);
            NextState = ST_RD_CRC16_2;
        break;

        case ST_RD_CRC16_2: // ×òåíèå ìëàäøåãî áàéòà CRC16
            printf("%s CRC16_2=0x%X\n", __FUNCTION__, Val);
            NextState = ST_WR_DATA_RESP;
        break;

        default:
            printf("%s Unknown St = 0x%X, Val = 0x%X\n", __FUNCTION__, CurrState, Val);
            return;
    }

    CurrState = NextState;
}

u8 TSdCard::Rd()
{
//    printf(__FUNCTION__" cmd=0x%X, St=0x%X\n", Cmd, CurrState);
    if(!Image)
        return 0xFF;

    switch(Cmd)
    {
    case CMD_GO_IDLE_STATE:
        if(CurrState == ST_R1)
        {
//            Cmd = CMD_INVALID;
            CurrState = ST_IDLE;
            return 1;
        }
    break;
    case CMD_SEND_OP_COND:
        if(CurrState == ST_R1)
        {
//            Cmd = CMD_INVALID;
            CurrState = ST_IDLE;
            return 0;
        }
    break;
    case CMD_SET_BLOCKLEN:
        if(CurrState == ST_R1)
        {
//            Cmd = CMD_INVALID;
            CurrState = ST_IDLE;
            return 0;
        }
    break;
    case CMD_SEND_IF_COND:
        if(CurrState == ST_R7)
        {
            CurrState = ST_IDLE;
            return 5; // invalid command | idle state
        }
    break;

    case CMD_READ_OCR:
        if(CurrState == ST_R1)
        {
            CurrState = ST_R3;
            return 0;
        }
    break;

    case CMD_APP_CMD:
        if(CurrState == ST_R1)
        {
            CurrState = ST_IDLE;
            return 0;
        }
    break;

    case CMD_SET_WR_BLK_ERASE_COUNT:
        if(CurrState == ST_R1)
        {
            CurrState = ST_IDLE;
            return 0;
        }
    break;

    case CMD_SD_SEND_OP_COND:
        if(CurrState == ST_R1)
        {
            CurrState = ST_IDLE;
            return 0;
        }
    break;

    case CMD_CRC_ON_OFF:
        if(CurrState == ST_R1)
        {
            CurrState = ST_IDLE;
            return 0;
        }
    break;

    case CMD_STOP_TRANSMISSION:
        switch(CurrState)
        {
        case ST_R1:
            CurrState = ST_R1b;
            return 0;
        case ST_R1b:
            CurrState = ST_IDLE;
            return 0xFF;
        }
    break;

    case CMD_READ_SINGLE_BLOCK:
        switch(CurrState)
        {
        case ST_R1: // Îòâåò íà êîìàíäó (êàðòà->õîñò)
            CurrState = ST_WR_DATA_SIG;
            return 0;
        case ST_WR_DATA_SIG: // Òîêåí äàííûõ (êàðòà->õîñò)
            DataCnt = 0;
            CurrState = ST_WR_DATA;
            return 0xFE;
        case ST_WR_DATA: // Ïåðåäà÷à äàííûõ (êàðòà->õîñò)
        {
            u8 Val = Buf[DataCnt++];
            if(DataCnt == DataBlockLen)
            {
                DataCnt = 0;
                CurrState = ST_WR_CRC16_1;
            }
            return Val;
        }
        case ST_WR_CRC16_1: // Ïåðåäà÷à crc16 (êàðòà->õîñò)
            CurrState = ST_WR_CRC16_2;
            return 0xFF;
        case ST_WR_CRC16_2: // Ïåðåäà÷à crc16 (êàðòà->õîñò)
            CurrState = ST_IDLE;
            Cmd = CMD_INVALID;
            return 0xFF;
        }
//        Cmd = CMD_INVALID;
    break;

    case CMD_READ_MULTIPLE_BLOCK:
        switch(CurrState)
        {
        case ST_R1: // Îòâåò íà êîìàíäó (êàðòà->õîñò)
            CurrState = ST_WR_DATA_SIG;
            return 0;
        case ST_WR_DATA_SIG: // Òîêåí äàííûõ (êàðòà->õîñò)
            DataCnt = 0;
            CurrState = ST_IDLE;
            return 0xFE;
        case ST_IDLE: // Ïåðåäà÷à äàííûõ (êàðòà->õîñò), ïðåðûâàåòñÿ êîìàíäîé CMD_STOP_TRANSMISSION
        {
            u8 Val = Buf[DataCnt++];
            if(DataCnt == DataBlockLen)
            {
                DataCnt = 0;
                fread(Buf, 512, 1, Image);
                CurrState = ST_WR_CRC16_1;
            }
            return Val;
        }
        case ST_WR_CRC16_1: // Ïåðåäà÷à crc16 (êàðòà->õîñò)
            CurrState = ST_WR_CRC16_2;
            return 0xFF;
        case ST_WR_CRC16_2: // Ïåðåäà÷à crc16 (êàðòà->õîñò)
            CurrState = ST_WR_DATA_SIG;
            return 0xFF;
        }
    break;

    case CMD_SEND_CSD:
        switch(CurrState)
        {
        case ST_R1:
            CurrState = ST_WR_DATA_SIG;
            return 0;
        case ST_WR_DATA_SIG:
            CurrState = ST_WR_DATA;
            return 0xFE;
        case ST_WR_DATA:
        {
            u8 Val = Csd[CsdCnt++];
            if(CsdCnt == 16)
            {
                CsdCnt = 0;
                CurrState = ST_IDLE;
                Cmd = CMD_INVALID;
            }
            return Val;
        }
        }
//        Cmd = CMD_INVALID;
    break;

    case CMD_SEND_CID:
        switch(CurrState)
        {
        case ST_R1:
            CurrState = ST_WR_DATA_SIG;
            return 0x00;
        case ST_WR_DATA_SIG:
            CurrState = ST_WR_DATA;
            return 0xFE;
        case ST_WR_DATA:
        {
            u8 Val = Cid[CidCnt++];
            if(CidCnt == 16)
            {
                CidCnt = 0;
                CurrState = ST_IDLE;
                Cmd = CMD_INVALID;
            }
            return Val;
        }
        }
//        Cmd = CMD_INVALID;
    break;

    case CMD_WRITE_BLOCK:
//        printf(__FUNCTION__" cmd=0x%X, St=0x%X\n", Cmd, CurrState);
        switch(CurrState)
        {
        case ST_R1:
            CurrState = ST_RD_DATA_SIG;
            return 0;

        case ST_WR_DATA_RESP:
        {
            CurrState = ST_IDLE;
            u8 Resp = ((STAT_DATA_ACCEPTED) << 1) | 1;
            return Resp;
        }
        }
    break;

    case CMD_WRITE_MULTIPLE_BLOCK:
        switch(CurrState)
        {
        case ST_R1:
            CurrState = ST_RD_DATA_SIG_MUL;
            return 0;
        case ST_WR_DATA_RESP:
        {
            CurrState = ST_RD_DATA_SIG_MUL;
            u8 Resp = ((STAT_DATA_ACCEPTED) << 1) | 1;
            return Resp;
        }
        }
    break;

    default:
        if(!((CurrState == ST_IDLE) && (Cmd == CMD_INVALID)))
        {
            printf("%s Unknown CMD = 0x%X\n", __FUNCTION__, Cmd);
        }

        if(Cmd != CMD_INVALID)
        {
            return 4; // illegal command
        }
    }

    if(CurrState == ST_R3)
    {
        u8 Val = OcrArr[3 - OcrCnt++];

        if(OcrCnt == 4)
        {
            CurrState = ST_IDLE;
            OcrCnt = 0;
        }
        return Val;
    }
    return 0xFF;
}

TSdCard::TState TSdCard::GetRespondType()
{
    if(!AppCmd)
    {
        switch(Cmd)
        {
        case CMD_APP_CMD:
            AppCmd = true;
        case CMD_GO_IDLE_STATE:
        case CMD_SEND_OP_COND:
        case CMD_SET_BLOCKLEN:
        case CMD_READ_SINGLE_BLOCK:
        case CMD_READ_MULTIPLE_BLOCK:
        case CMD_CRC_ON_OFF:
        case CMD_STOP_TRANSMISSION:
        case CMD_SEND_CSD:
        case CMD_SEND_CID:
        case CMD_WRITE_BLOCK:
        case CMD_WRITE_MULTIPLE_BLOCK:
            return ST_R1;
        case CMD_READ_OCR:
            return ST_R1; // R3
        case CMD_SEND_IF_COND:
            return ST_R7;
        default:
            printf("%s Unknown CMD = 0x%X\n", __FUNCTION__, Cmd);
            return ST_R1;
        }
    }
    else
    {
        AppCmd = false;
        switch(Cmd)
        {
            case CMD_SET_WR_BLK_ERASE_COUNT:
            case CMD_SD_SEND_OP_COND:
                AppCmd = false;
                return ST_R1;
            default:
                printf("%s Unknown ACMD = 0x%X\n", __FUNCTION__, Cmd);
        }
    }

    return ST_IDLE;
}

void TSdCard::Open(const char *Name)
{
//    printf(__FUNCTION__"\n");
    assert(!Image);
    Image = fopen(Name, "r+b");
    if(!Image)
    {
        if(Name[0])
        {
            errmsg("can't find SD card image `%s'", Name);
        }
        return;
    }
    ImageSize = u32(_filelengthi64(fileno(Image)) / (512 * 1024)) - 1;
    UpdateCsdImageSize();
}

void TSdCard::Close()
{
    if(Image)
    {
        fclose(Image);
        Image = nullptr;
    }
}

TSdCard SdCard;