/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*        http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

/**
* @file sd_spi.c
* @brief support spi-sd dev function using spi bus driver framework
* @version 1.0 
* @author AIIT XUOS Lab
* @date 2021-04-24
*/

#include <sd_spi.h>

static struct SpiSdDevice g_spi_sd_dev;
static struct SdCmdParam g_sd_cmd_param;

static uint32 SdReady(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    uint8 data = 0xFF;
    uint8 read;
    uint32 start_time;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    write_param.buffer = (void *)&data;
    write_param.size = 1;
    read_param.buffer = (void *)&read;
    read_param.size = 1;

    start_time = 0;
    do
    {
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

        BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

        SD_TIMEOUT(start_time, 10 * SPI_SD_TIMEOUT_NUM);
    }while(0xFF != read);

    return EOK;
}

static uint32 SdSendCmdByte(SpiSdDeviceType spi_sd_dev, struct SdCmdParam *sd_cmd_param)
{
    NULL_PARAM_CHECK(spi_sd_dev);
    NULL_PARAM_CHECK(&spi_sd_dev->spi_dev->haldev);
    NULL_PARAM_CHECK(sd_cmd_param);

    x_err_t ret = EOK;
    uint32 start_time;
    uint8 i;
    uint8 write[8], read[8];
    uint8 write_byte, read_byte;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    ret = SdReady(spi_sd_dev);
    if (EOK != ret) {
        return ret;
    }

    /*8 Bytes CMD : \0xFF\(CMD \ 0x40)\CMD ARG0\CMD ARG1\CMD ARG2\CMD ARG3\(CRC << 1 \ 0x1)\0xFF\*/
    write[0] = 0xFF;
    write[1] = sd_cmd_param->sd_cmd_type | 0x40;
    for (i = 2; i < 6; i ++) {
        write[i] = (uint8)(sd_cmd_param->sd_cmd_args >> ((5- i) * 8) );
    }
    write[6] = (uint8)sd_cmd_param->sd_cmd_crc;//CRC is not valid using SPI SD

    write[7] = 0xFF;

    write_param.buffer = (void *)write;
    write_param.size = 8;
    BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

    start_time = 0;
    do
    {
        read_param.buffer = (void *)&read;
        read_param.size = 1;
        BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

        if ((SD_CMD_17  == sd_cmd_param->sd_cmd_type) || (SD_CMD_18  == sd_cmd_param->sd_cmd_type)) {
            MdelayKTask(100);
        }

        SD_TIMEOUT(start_time, 2 * SPI_SD_TIMEOUT_NUM);
    }while((0 != (read[0] & 0x80)));

    switch (sd_cmd_param->sd_respone_type)
    {
        case SD_RESPONE_1 :
            sd_cmd_param->sd_respone_data[0] = read[0];
            return EOK;
        case SD_RESPONE_1B :
            sd_cmd_param->sd_respone_data[0] = read[0];

            start_time = 0;
            do
            {
                read_param.buffer = (void *)&read_byte;
                read_param.size = 1;
                BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

                SD_TIMEOUT(start_time, 2 * SPI_SD_TIMEOUT_NUM);
            }while(0xFF != read_byte);

            return EOK;
        case SD_RESPONE_2 :
            sd_cmd_param->sd_respone_data[0] = read[0];

            read_param.buffer = (void *)&read_byte;
            read_param.size = 1;
            BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

            sd_cmd_param->sd_respone_data[1] = read_byte;

            return EOK;
        case SD_RESPONE_3 :
        case SD_RESPONE_7 :
            sd_cmd_param->sd_respone_data[0] = read[0];

            read_param.buffer = (void *)&read;
            read_param.size = 4;
            BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

            sd_cmd_param->sd_respone_data[1] = read[0];
            sd_cmd_param->sd_respone_data[2] = read[1];
            sd_cmd_param->sd_respone_data[3] = read[2];
            sd_cmd_param->sd_respone_data[4] = read[3];

            return EOK;
        default:
            break;
    }

    KPrintf("SdSendCmdByte not support respone type %u\n", sd_cmd_param->sd_respone_type);
    return ERROR;
}

static uint32 SdSpiConfigure(struct Driver *spi_drv, struct SpiMasterParam *spi_master_param)
{
    NULL_PARAM_CHECK(spi_drv);
    NULL_PARAM_CHECK(spi_master_param);
    x_err_t ret = EOK;

    struct BusConfigureInfo configure_info;

    configure_info.configure_cmd = OPE_CFG;
    configure_info.private_data = (void *)spi_master_param;
    ret = BusDrvConfigure(spi_drv, &configure_info);
    if (ret) {
        KPrintf("spi drv OPE_CFG error drv %8p cfg %8p\n", spi_drv, spi_master_param);
        return ERROR;
    }

    configure_info.configure_cmd = OPE_INT;
    ret = BusDrvConfigure(spi_drv, &configure_info);
    if (ret) {
        KPrintf("spi drv OPE_INT error drv %8p\n", spi_drv);
        return ERROR;
    }
    
    return ret;
}

static void SdHwInitCs(SpiSdDeviceType spi_sd_dev)
{
    uint8 i;
    uint8 data = 0xFF;

    struct BusBlockWriteParam write_param;

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    for (i = 0 ; i < 10 ; i ++) {
        write_param.buffer = (void *)&data;
        write_param.size = 1;
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);
    }
}

static uint32 SdHwInit(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint32 start_time;

    g_sd_cmd_param.sd_cmd_type = SD_CMD_0;
    g_sd_cmd_param.sd_cmd_args = 0x00;
    g_sd_cmd_param.sd_cmd_crc = 0x95;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    start_time = 0;

    do
    {
        /*pull down the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

        ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
        if (EOK != ret) {
            KPrintf("SdHwInit send CMD0 error %d\n", ret);
        }

        /*pull up the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

        SD_TIMEOUT(start_time, 3 * SPI_SD_TIMEOUT_NUM);
    }while(0x01 != g_sd_cmd_param.sd_respone_data[0]);

    return EOK;
}

static uint32 SdConfirmType(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint32 start_time;

    g_sd_cmd_param.sd_cmd_type = SD_CMD_8;
    g_sd_cmd_param.sd_cmd_args = 0x01AA;
    g_sd_cmd_param.sd_cmd_crc = 0x87;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_7;

    start_time = 0;

    do
    {
        /*pull down the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

        ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
        if (EOK != ret) {
            KPrintf("SdConfirmType send CMD8 error %d\n", ret);
        }

        /*pull up the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

        /*Only SD2.0 support CMD8, return 0x01*/
        if (0x01 == g_sd_cmd_param.sd_respone_data[0]) {
            spi_sd_dev->sd_param.sd_type = SD_TYPE_V2;

            if (0x01 != g_sd_cmd_param.sd_respone_data[3]) {
                KPrintf("SdConfirmType CMD8 working voltage is not 2.0V\n");
                return ERROR;
            }
        } else {
            spi_sd_dev->sd_param.sd_type = SD_TYPE_V1;
        }

        SD_TIMEOUT(start_time, 3 * SPI_SD_TIMEOUT_NUM);
    }while(0xAA != g_sd_cmd_param.sd_respone_data[4]);

    return EOK;
}

static uint32 SdHwReset(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint8 sd_mmc_flag = 0;
    uint32 start_time;

    if (SD_TYPE_V2 == spi_sd_dev->sd_param.sd_type) {
        start_time = 0;
        do
        {
            /*Step1 : CMD55, return 0x01*/
            g_sd_cmd_param.sd_cmd_type = SD_CMD_55;
            g_sd_cmd_param.sd_cmd_args = 0x00;
            g_sd_cmd_param.sd_cmd_crc = 0x65;
            g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;
            
            /*pull down the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

            ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
            if (EOK != ret) {
                KPrintf("SdHwReset type 2.0 send CMD55 error %d\n", ret);
            }

            if (0x01 != g_sd_cmd_param.sd_respone_data[0]) {
                KPrintf("SdHwReset type 2.0 send CMD55 respone error 0x%x\n", g_sd_cmd_param.sd_respone_data[0]);
            }

            /*Step2 : ACMD41,return 0x00*/
            g_sd_cmd_param.sd_cmd_type = SD_ACMD_41;
            g_sd_cmd_param.sd_cmd_args = 0x40000000;
            g_sd_cmd_param.sd_cmd_crc = 0x77;
            g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

            ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
            if (EOK != ret) {
                KPrintf("SdHwReset type 2.0 send ACMD41 error %d\n", ret);
            }

            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

            SD_TIMEOUT(start_time, SPI_SD_TIMEOUT_NUM);
        }while(0x00 != g_sd_cmd_param.sd_respone_data[0]);

        /*Step3 : CMD58, read OCR to verify whether sd 2.0 is SDHC or not*/
        g_sd_cmd_param.sd_cmd_type = SD_CMD_58;
        g_sd_cmd_param.sd_cmd_args = 0x00;
        g_sd_cmd_param.sd_cmd_crc = 0x00;
        g_sd_cmd_param.sd_respone_type = SD_RESPONE_3;
            
        /*pull down the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

        ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
        if (EOK != ret) {
            KPrintf("SdHwReset type 2.0 send CMD58 error %d\n", ret);

            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);  
            return ERROR;
        }

        /*pull up the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);      

        if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
            KPrintf("SdHwReset type 2.0 send CMD58 respone error 0x%x\n", g_sd_cmd_param.sd_respone_data[0]);
            return ERROR;
        }

        if (g_sd_cmd_param.sd_respone_data[1] >> 2) {
            KPrintf("SdHwReset SD 2.0 is SDHC!\n");
            spi_sd_dev->sd_param.sd_type = SD_TYPE_SDHC;
        }

        KPrintf("SdHwReset SD 2.0 done!\n");
        return EOK;
    } else if (SD_TYPE_V1 == spi_sd_dev->sd_param.sd_type) {
        start_time = 0;
        do
        {
            /*Step1 : CMD55, return 0x01*/
            g_sd_cmd_param.sd_cmd_type = SD_CMD_55;
            g_sd_cmd_param.sd_cmd_args = 0x00;
            g_sd_cmd_param.sd_cmd_crc = 0x65;
            g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;
            
            /*pull down the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

            ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
            if (EOK != ret) {
                KPrintf("SdHwReset type 1.0 send CMD55 error %d\n", ret);
            }

            if (0x01 != g_sd_cmd_param.sd_respone_data[0]) {
                KPrintf("SdHwReset type 1.0 send CMD55 respone 0x%x, might be MMC\n", g_sd_cmd_param.sd_respone_data[0]);
                break;
            }

            /*Step2 : ACMD41,return 0x00*/
            g_sd_cmd_param.sd_cmd_type = SD_ACMD_41;
            g_sd_cmd_param.sd_cmd_args = 0x40000000;
            g_sd_cmd_param.sd_cmd_crc = 0x77;
            g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

            ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
            if (EOK != ret) {
                KPrintf("SdHwReset type 1.0 send ACMD41 error %d\n", ret);
            }

            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

            if ((0x00 != g_sd_cmd_param.sd_respone_data[0]) || (0x01 != g_sd_cmd_param.sd_respone_data[0])) {
                KPrintf("SdHwReset type 1.0 send ACMD41 respone 0x%x, might be MMC\n", g_sd_cmd_param.sd_respone_data[0]);
                sd_mmc_flag = 1;
                break;
            }

            SD_TIMEOUT(start_time, SPI_SD_TIMEOUT_NUM);
        }while(0x00 != g_sd_cmd_param.sd_respone_data[0]);

        if (sd_mmc_flag) {
            SdHwInitCs(spi_sd_dev);
            
            /*Step1 : CMD0, enter IDLE, return 0x01*/
            ret = SdHwInit(spi_sd_dev);
            if (EOK != ret) {
                KPrintf("SdHwReset MMC make sd card enter idle error %d using CMD0\n", ret);
            }

            start_time = 0;

            /*Step2 : CMD1,return 0x00*/
            do
            {
                g_sd_cmd_param.sd_cmd_type = SD_CMD_1;
                g_sd_cmd_param.sd_cmd_args = 0x00;
                g_sd_cmd_param.sd_cmd_crc = 0x00;
                g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

                /*pull down the cs pin*/
                SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

                ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
                if (EOK != ret) {
                    KPrintf("SdHwReset type MMC send CMD1 error %d\n", ret);
                }

                /*pull up the cs pin*/
                SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

                SD_TIMEOUT(start_time, SPI_SD_TIMEOUT_NUM);
            }while(0x00 != g_sd_cmd_param.sd_respone_data[0]);

            KPrintf("SdHwReset SD 1.0 is MMC!\n");
            spi_sd_dev->sd_param.sd_type = SD_TYPE_MMC;
            return EOK;
        }
    } else {
        KPrintf("SdHwReset do not support the sd type %d\n", spi_sd_dev->sd_param.sd_type);
        return ERROR;
    }
}

static uint32 SdHwSetBlockLength(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;

    g_sd_cmd_param.sd_cmd_type = SD_CMD_16;
    g_sd_cmd_param.sd_cmd_args = SD_BLOCK_LENGTH;
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdHwSetBlockLength send CMD16 error %d\n", ret);
    }

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdHwSetBlockLength CMD16 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    spi_sd_dev->sd_param.block_param.block_size = SD_BLOCK_LENGTH;
    spi_sd_dev->sd_param.block_param.sector_bytes = SD_BLOCK_LENGTH;

    return EOK;
}

static void SdGetCSDv1(SpiSdDeviceType spi_sd_dev)
{
    /*CSD reg bit[103 : 96]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_transpeed = spi_sd_dev->sd_param.csd_data.sd_csd_data[3];

    /*CSD reg bit[83 : 80]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_readbl_len = spi_sd_dev->sd_param.csd_data.sd_csd_data[5] & 0x0F;

    /*CSD reg bit[73 : 62]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_csize = 
        ((uint16)(spi_sd_dev->sd_param.csd_data.sd_csd_data[6] & 0x03) << 10) + 
        (uint16)(spi_sd_dev->sd_param.csd_data.sd_csd_data[7] << 2) + 
        (spi_sd_dev->sd_param.csd_data.sd_csd_data[8] >> 6);

    /*CSD reg bit[49 : 47]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_csize_multi = 
        ((spi_sd_dev->sd_param.csd_data.sd_csd_data[9] & 0x03) << 1) + 
        ((spi_sd_dev->sd_param.csd_data.sd_csd_data[10] & 0x80) >> 7);

    /*memory capacity = BLOCKNR*BLOCK_LEN Bytes*/
    /*memory capacity = (C_SIZE+1)*2^(C_SIZE_MULT+2+READ_BL_LEN) Bytes*/
    spi_sd_dev->sd_param.csd_data.sd_csd_capacity = 
        (spi_sd_dev->sd_param.csd_data.sd_csd_csize + 1) *
        (1 << (spi_sd_dev->sd_param.csd_data.sd_csd_csize_multi + 2 + spi_sd_dev->sd_param.csd_data.sd_csd_readbl_len));

    spi_sd_dev->sd_param.block_param.sector_num = 
        spi_sd_dev->sd_param.csd_data.sd_csd_capacity / spi_sd_dev->sd_param.block_param.sector_bytes;

    KPrintf("SdGetCSDv1 transpeed %d read_bl_size %d c_size %d c_size_mult %d capacity %d MB\n",
        spi_sd_dev->sd_param.csd_data.sd_csd_transpeed,
        spi_sd_dev->sd_param.csd_data.sd_csd_readbl_len,
        spi_sd_dev->sd_param.csd_data.sd_csd_csize,
        spi_sd_dev->sd_param.csd_data.sd_csd_csize_multi,
        spi_sd_dev->sd_param.csd_data.sd_csd_capacity / (1024 * 1024));
}

static void SdGetCSDv2(SpiSdDeviceType spi_sd_dev)
{
    /*CSD reg bit[103 : 96]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_transpeed = spi_sd_dev->sd_param.csd_data.sd_csd_data[3];

    /*CSD reg bit[69 : 48]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_csize = 
        (uint32)((spi_sd_dev->sd_param.csd_data.sd_csd_data[7] & 0x3F) << 16) +
        (uint32)(spi_sd_dev->sd_param.csd_data.sd_csd_data[8] << 8) +
        spi_sd_dev->sd_param.csd_data.sd_csd_data[9];

    /*memory capacity = (C_SIZE+1)*512 KBytes*/
    spi_sd_dev->sd_param.csd_data.sd_csd_capacity = 
        (spi_sd_dev->sd_param.csd_data.sd_csd_csize + 1) * 512;

    spi_sd_dev->sd_param.block_param.sector_num = 
        spi_sd_dev->sd_param.csd_data.sd_csd_capacity / spi_sd_dev->sd_param.block_param.sector_bytes;

    KPrintf("SdGetCSDv1 transpeed %d c_size %d capacity %d.%d GB\n",
        spi_sd_dev->sd_param.csd_data.sd_csd_transpeed,
        spi_sd_dev->sd_param.csd_data.sd_csd_csize,
        spi_sd_dev->sd_param.csd_data.sd_csd_capacity / (1024 * 1024),
        ((spi_sd_dev->sd_param.csd_data.sd_csd_capacity / 1024 ) % 1024) * 100 / 1024);
}

static uint32 SdGetMMCCSDParam(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    if (spi_sd_dev->sd_param.csd_data.sd_csd_structure > 2) {
        KPrintf("SdGetMMCCSDParam csd structure error %d\n", spi_sd_dev->sd_param.csd_data.sd_csd_structure);
        return ERROR;
    }

    SdGetCSDv1(spi_sd_dev);

    switch (spi_sd_dev->sd_param.csd_data.sd_csd_transpeed & 0x03)
    {
    case 0 :
        spi_sd_dev->sd_param.sd_spi_maxfreq = 100 * 1000;
        break;
    case 1 :
        spi_sd_dev->sd_param.sd_spi_maxfreq = 1 * 1000 * 1000;
        break;
    case 2 :
        spi_sd_dev->sd_param.sd_spi_maxfreq = 10 * 1000 * 1000;
        break;
    case 3 :
        spi_sd_dev->sd_param.sd_spi_maxfreq = 100 * 1000 * 1000;
        break;
    default:
        KPrintf("SdGetMMCCSDParam sd_csd_transpeed error %d\n", spi_sd_dev->sd_param.csd_data.sd_csd_transpeed);
        spi_sd_dev->sd_param.sd_spi_maxfreq = 100 * 1000;
        break;
    }

    return EOK;
}

static uint32 SdGetCSDParam(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    if (spi_sd_dev->sd_param.csd_data.sd_csd_structure > 1) {
        KPrintf("SdGetCSDParam csd structure error %d\n", spi_sd_dev->sd_param.csd_data.sd_csd_structure);
        return ERROR;
    }

    /*CSD v2.0*/
    if (1 == spi_sd_dev->sd_param.csd_data.sd_csd_structure) {
        SdGetCSDv2(spi_sd_dev);

        switch (spi_sd_dev->sd_param.csd_data.sd_csd_transpeed)
        {
        case 0x32 :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 10 * 1000 * 1000;
            break;
        case 0x5A :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 50 * 1000 * 1000;
            break;
        case 0x0B :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 100 * 1000 * 1000;
            break;
        case 0x2B :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 200 * 1000 * 1000;
            break;
        default:
            KPrintf("SdGetCSDParam 2.0 sd_csd_transpeed %d\n", spi_sd_dev->sd_param.csd_data.sd_csd_transpeed);
            spi_sd_dev->sd_param.sd_spi_maxfreq = 1 * 1000 * 1000;
            break;
        }
    }
    /*CSD v1.0*/
    else if (0 == spi_sd_dev->sd_param.csd_data.sd_csd_structure) {
        SdGetCSDv1(spi_sd_dev);

        switch (spi_sd_dev->sd_param.csd_data.sd_csd_transpeed)
        {
        case 0x32 :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 10 * 1000 * 1000;
            break;
        case 0x5A :
            spi_sd_dev->sd_param.sd_spi_maxfreq = 50 * 1000 * 1000;
            break;
        default:
            KPrintf("SdGetCSDParam 1.0 sd_csd_transpeed %d\n", spi_sd_dev->sd_param.csd_data.sd_csd_transpeed);
            spi_sd_dev->sd_param.sd_spi_maxfreq = 1 * 1000 * 1000;
            break;
        }
    }

    return EOK;
}

static uint32 SdVerifyCSD(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;

    /*CSD reg bit[127 : 126]*/
    spi_sd_dev->sd_param.csd_data.sd_csd_structure = spi_sd_dev->sd_param.csd_data.sd_csd_data[0] >> 6;
    KPrintf("SdVerifyCSD csd structure %d type %d\n", 
        spi_sd_dev->sd_param.csd_data.sd_csd_structure,
        spi_sd_dev->sd_param.sd_type);

    switch (spi_sd_dev->sd_param.sd_type)
    {
        case SD_TYPE_UNKNOW :
            ret = ERROR;
            break;
        case SD_TYPE_MMC :
            ret = SdGetMMCCSDParam(spi_sd_dev);
            break;
        case SD_TYPE_V1 :
        case SD_TYPE_V2 :
        case SD_TYPE_SDHC :
        case SD_TYPE_SDXC :
            ret = SdGetCSDParam(spi_sd_dev);
            break;
        default:
            break;
    }

    return ret;
}

static uint32 SdHwReadCSD(SpiSdDeviceType spi_sd_dev)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint8 i;
    uint8 read[SD_CMD_CSD_LENGTH];

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    /*Step1 : CMD9, return 0x00*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_9;
    g_sd_cmd_param.sd_cmd_args = 0x00;
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_2;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdHwReadCSD send CMD9 error %d\n", ret);
        return ERROR;
    }

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdHwReadCSD CMD9 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    if (0xFE != g_sd_cmd_param.sd_respone_data[1]) {
        /*Step2 : SPI write data 0xFF until read 0xFE*/
        uint8 data = 0xFF;
        uint8 read_spi; 
        uint32 start_time;

        write_param.buffer = (void *)&data;
        write_param.size = 1;
        read_param.buffer = (void *)&read_spi;
        read_param.size = 1;

        start_time = 0;

        do
        {
            BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);
            BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

            SD_TIMEOUT(start_time, 10 * SPI_SD_TIMEOUT_NUM);
        }while(0xFE != read_spi);
    }

    /*Step3 : SPI read 16 bytes CSD register data*/
    read_param.buffer = (void *)read;
    read_param.size = SD_CMD_CSD_LENGTH;
    BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

    memcpy(spi_sd_dev->sd_param.csd_data.sd_csd_data, read, SD_CMD_CSD_LENGTH);

    /*Step4 : SPI read 2 bytes CRC*/
    read_param.buffer = (void *)read;
    read_param.size = 2;
    BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

    /*Step5 : verify CSD data*/
    ret = SdVerifyCSD(spi_sd_dev);
    if (EOK != ret) {
        KPrintf("SdHwReadCSD verify data error %d\n", ret);
        return ERROR;
    }

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    return EOK;
}

static uint32 SdReadSingleBlock(SpiSdDeviceType spi_sd_dev, uint32 id, uint8 *read_buffer)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    /*Step1 : CMD17, return 0x00*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_17;
    if (SD_TYPE_SDHC == spi_sd_dev->sd_param.sd_type) {
        g_sd_cmd_param.sd_cmd_args = id;
    } else {
        g_sd_cmd_param.sd_cmd_args = id * spi_sd_dev->sd_param.block_param.block_size;
    }
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdReadSingleBlock send CMD17 error %d\n", ret);
        return ERROR;
    }

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdReadSingleBlock CMD17 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    /*Step2 : SPI write data 0xFF until read 0xFE*/
    uint8 data = 0xFF;
    uint8 read[2];
    uint32 start_time;

    write_param.buffer = (void *)&data;
    write_param.size = 1;
    read_param.buffer = (void *)read;
    read_param.size = 1;

    start_time = 0;

    do
    {
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);
        BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

        SD_TIMEOUT(start_time, 100 * SPI_SD_TIMEOUT_NUM);
    }while(0xFE != read[0]);

    /*Step3 : SPI read single block size data*/
    read_param.buffer = (void *)read_buffer;
    read_param.size = spi_sd_dev->sd_param.block_param.block_size;
    BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

    /*Step4 : SPI read 2 bytes CRC*/
    read_param.buffer = (void *)read;
    read_param.size = 2;
    BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    return EOK;
}

static uint32 SdReadMultiBlock(SpiSdDeviceType spi_sd_dev, uint32 id, const uint8 *read_buffer, uint32 block_num)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    /*Step1 : CMD18, return 0x00*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_18;
    if (SD_TYPE_SDHC == spi_sd_dev->sd_param.sd_type) {
        g_sd_cmd_param.sd_cmd_args = id;
    } else {
        g_sd_cmd_param.sd_cmd_args = id * spi_sd_dev->sd_param.block_param.block_size;
    }
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdReadMultiBlock send CMD18 error %d\n", ret);
        return ERROR;
    }

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdReadMultiBlock CMD18 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    /*Step2 : SPI write data 0xFF until read 0xFE*/
    uint32 i = 0;
    uint8 data = 0xFF;
    uint8 read[2];
    uint32 start_time;

    for (i = 0 ; i < block_num ; i ++) {
        write_param.buffer = (void *)&data;
        write_param.size = 1;
        read_param.buffer = (void *)read;
        read_param.size = 1;

        start_time = 0;

        do
        {
            BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);
            BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

            SD_TIMEOUT(start_time, 10 * SPI_SD_TIMEOUT_NUM);
        }while(0xFE != read[0]);

        /*Step3 : SPI read multi block size data*/
        read_param.buffer = (void *)((uint8 *)read_buffer + i * spi_sd_dev->sd_param.block_param.block_size);
        read_param.size = spi_sd_dev->sd_param.block_param.block_size;
        BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);
    }

    /*Step4 : SPI read 2 bytes CRC*/
    read_param.buffer = (void *)read;
    read_param.size = 2;
    BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

    /*Step5 : CMD12 stop read*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_12;
    g_sd_cmd_param.sd_cmd_args = 0x00;
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1B;

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdReadMultiBlock send CMD12 error %d\n", ret);
        return ERROR;
    }

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    return EOK;
}

static uint32 SdWriteSingleBlock(SpiSdDeviceType spi_sd_dev, uint32 id, const uint8 *write_buffer)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint32 start_time;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    /*Step1 : CMD24, return 0x00*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_24;
    if (SD_TYPE_SDHC == spi_sd_dev->sd_param.sd_type) {
        g_sd_cmd_param.sd_cmd_args = id;
    } else {
        g_sd_cmd_param.sd_cmd_args = id * spi_sd_dev->sd_param.block_param.block_size;
    }
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    start_time = 0;
    do
    {
        ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
        if (EOK != ret) {
            KPrintf("SdWriteSingleBlock send CMD24 error %d\n", ret);
            return ERROR;
        }

        SD_TIMEOUT(start_time, SPI_SD_TIMEOUT_NUM);
    }while(0x00 != g_sd_cmd_param.sd_respone_data[0]);

    /*Step2 : SPI write data 0xFE*/
    uint8 data = 0xFE;
    uint8 read;
    uint8 write[2] = {0xFF, 0xFF};

    write_param.buffer = (void *)&data;
    write_param.size = 1;
    BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

    /*Step3 : SPI write single block size data*/
    write_param.buffer = (void *)write_buffer;
    write_param.size = spi_sd_dev->sd_param.block_param.block_size;
    BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

    /*Step4 : SPI write 2 bytes CRC*/
    write_param.buffer = (void *)write;
    write_param.size = 2;
    BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

    /*Step5 : SPI read respone xxx0 0101, write data done*/
    read_param.buffer = (void *)&read;
    read_param.size = 1;

    start_time = 0;
    do
    {
        BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

        SD_TIMEOUT(start_time, 10 * SPI_SD_TIMEOUT_NUM);
    }while(0x05 != (read & 0x1F));
    
    /*Step6 : SPI read respone 0xFF, write done*/
    ret = SdReady(spi_sd_dev);
    if (EOK != ret) {
        KPrintf("SdWriteSingleBlock SdReady error %d\n", ret);
        return ERROR;
    }

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    return EOK;
}

static uint32 SdWriteMultiBlock(SpiSdDeviceType spi_sd_dev, uint32 id, const void *write_buffer, uint32 block_num)
{
    NULL_PARAM_CHECK(spi_sd_dev);

    x_err_t ret = EOK;
    uint32 start_time;

    struct BusBlockWriteParam write_param;
    struct BusBlockReadParam read_param;

    /*pull down the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 1, 0);

    /*Step1 : CMD55 + ACMD23 erase block*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_55;
    g_sd_cmd_param.sd_cmd_args = 0x00;
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdWriteMultiBlock send CMD55 error %d\n", ret);
        return ERROR;
    }

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdWriteMultiBlock CMD55 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    g_sd_cmd_param.sd_cmd_type = SD_ACMD_23;
    g_sd_cmd_param.sd_cmd_args = block_num;
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
    if (EOK != ret) {
        KPrintf("SdWriteMultiBlock send CMD55 error %d\n", ret);
        return ERROR;
    }

    if (0x00 != g_sd_cmd_param.sd_respone_data[0]) {
        KPrintf("SdWriteMultiBlock ACMD23 respone error %d\n", g_sd_cmd_param.sd_respone_data[0]);
        return ERROR;
    }

    /*Step2 : CMD25, return 0x00*/
    g_sd_cmd_param.sd_cmd_type = SD_CMD_25;
    if (SD_TYPE_SDHC == spi_sd_dev->sd_param.sd_type) {
        g_sd_cmd_param.sd_cmd_args = id;
    } else {
        g_sd_cmd_param.sd_cmd_args = id * spi_sd_dev->sd_param.block_param.block_size;
    }
    g_sd_cmd_param.sd_cmd_crc = 0x00;
    g_sd_cmd_param.sd_respone_type = SD_RESPONE_1;

    start_time = 0;
    do
    {
        ret = SdSendCmdByte(spi_sd_dev, &g_sd_cmd_param);
        if (EOK != ret) {
            KPrintf("SdWriteMultiBlock send CMD25 error %d\n", ret);
            return ERROR;
        }

        SD_TIMEOUT(start_time, SPI_SD_TIMEOUT_NUM);
    }while(0x00 != g_sd_cmd_param.sd_respone_data[0]);

    /*Step3 : SPI write data 0xFC*/
    uint32 i;
    uint8 data = 0xFC;
    uint8 read;
    uint8 write[2] = {0xFF, 0xFF};

    for (i = 0 ; i < block_num; i ++) {
        write_param.buffer = (void *)&data;
        write_param.size = 1;
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

        /*Step4 : SPI write multi block size data*/
        write_param.buffer = (void *)((uint8 *)write_buffer + i * spi_sd_dev->sd_param.block_param.block_size);
        write_param.size = spi_sd_dev->sd_param.block_param.block_size;
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

        /*Step5 : SPI write 2 bytes CRC*/
        write_param.buffer = (void *)write;
        write_param.size = 2;
        BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

        /*Step6 : SPI read respone xxx0 0101, single block write data done*/
        read_param.buffer = (void *)&read;
        read_param.size = 1;

        start_time = 0;
        do
        {
            BusDevReadData(&spi_sd_dev->spi_dev->haldev, &read_param);

            SD_TIMEOUT(start_time, 10 * SPI_SD_TIMEOUT_NUM);
        }while(0x05 != (read & 0x1F));
    
        /*Step7 : SPI read respone 0xFF, single block write done*/
        ret = SdReady(spi_sd_dev);
        if (EOK != ret) {
            KPrintf("SdWriteMultiBlock i %d SdReady error %d\n", i, ret);
            return ERROR;
        }
    }

    /*Step8 : SPI write 0xFD, multi block write data done*/
    write_param.buffer = (void *)&data;
    write_param.size = 1;
    BusDevWriteData(&spi_sd_dev->spi_dev->haldev, &write_param);

    /*Step9 : SPI read respone 0xFF, multi block write done*/
    ret = SdReady(spi_sd_dev);
    if (EOK != ret) {
        KPrintf("SdWriteMultiBlock final SdReady error %d\n", ret);
        return ERROR;
    }

    /*pull up the cs pin*/
    SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);

    return EOK;
}

uint32 SdOpen(void *dev)
{
    NULL_PARAM_CHECK(dev);

    SpiSdDeviceType spi_sd_dev;
    HardwareDevType haldev = (struct HardwareDev *)dev;
    struct SpiHardwareDevice *sd_dev;

    sd_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
    spi_sd_dev = CONTAINER_OF(sd_dev, struct SpiSdDevice, sd_dev);

    x_err_t ret = EOK;
    struct Driver *spi_drv = spi_sd_dev->spi_dev->haldev.owner_bus->owner_driver;

    /*Step1 : Configure SPI Low speed*/
    struct BusConfigureInfo configure_info;
    struct SpiMasterParam spi_master_param;
    spi_master_param.spi_data_bit_width = 8;
    spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
    spi_master_param.spi_maxfrequency = SPI_SD_FREQUENCY;//ensure the initialization successfully
    spi_master_param.spi_data_endian = 0;

    ret = spi_sd_dev->spi_dev->haldev.owner_bus->match(spi_drv, &spi_sd_dev->spi_dev->haldev);
    if (EOK != ret) {
        KPrintf("SD SPI dev match spi drv error!\n");
        return ret;
    }

    configure_info.private_data = (void *)&spi_master_param;
    ret = DeviceObtainBus(spi_sd_dev->spi_dev->haldev.owner_bus, &spi_sd_dev->spi_dev->haldev, spi_drv->drv_name, &configure_info);
    if (EOK != ret) {
        KPrintf("SD SPI obtain spi bus error!\n");
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    ret = SdSpiConfigure(spi_drv, &spi_master_param);
    if (EOK != ret) {
        KPrintf("SD SPI configure error!\n");
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    /*Step2 : Init the SD Card, pull up the cs pin for 74 clock*/
    SdHwInitCs(spi_sd_dev);

    /*Step3 : Init the SD Card using CMD0*/
    ret = SdHwInit(spi_sd_dev);
    if (EOK != ret) {
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    /*Step4 : Confirm the SD Card type using CMD8*/
    ret = SdConfirmType(spi_sd_dev);
    if (EOK != ret) {
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    /*Step5 : Reset the SD Card based on the card type*/
    ret = SdHwReset(spi_sd_dev);
    if (EOK != ret) {
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    /*Step6 : Set the block length*/
    ret = SdHwSetBlockLength(spi_sd_dev);
    if (EOK != ret) {
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ret;
    }

    /*Step7 : Read the CSD register data*/
    ret = SdHwReadCSD(spi_sd_dev);
    if (EOK != ret) {
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        /*pull up the cs pin*/
        SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);
        return ret;
    }

    /*Step8 : Configure SPI High speed*/
    spi_master_param.spi_data_bit_width = 8;
    spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
    spi_master_param.spi_maxfrequency = spi_sd_dev->sd_param.sd_spi_maxfreq;
    spi_master_param.spi_data_endian = 0;
    if (SdSpiConfigure(spi_drv, &spi_master_param)) {
        KPrintf("SD SPI configure error!\n");
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ERROR;
    }

    KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
    return EOK;
}

uint32 SdClose(void *dev)
{
    return EOK;
}

uint32 SdRead(void *dev, struct BusBlockReadParam *read_param)
{
    NULL_PARAM_CHECK(dev);

    SpiSdDeviceType spi_sd_dev;
    HardwareDevType haldev = (struct HardwareDev *)dev;
    struct SpiHardwareDevice *sd_dev;

    sd_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
    spi_sd_dev = CONTAINER_OF(sd_dev, struct SpiSdDevice, sd_dev);

    uint32 id = read_param->pos;
    uint32 block_num = read_param->size;
    uint8 *read_buffer = (uint8 *)read_param->buffer;

    if (0 == block_num) {
        KPrintf("SdRead block_num is 0 just return\n");
        return block_num;
    }

    x_err_t ret = EOK;
    struct Driver *spi_drv = spi_sd_dev->spi_dev->haldev.owner_bus->owner_driver;

    /*Step1 : SD Card Obtain SPI  BUS*/
    struct BusConfigureInfo configure_info;
    struct SpiMasterParam spi_master_param;
    spi_master_param.spi_data_bit_width = 8;
    spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
    spi_master_param.spi_maxfrequency = spi_sd_dev->sd_param.sd_spi_maxfreq;
    spi_master_param.spi_data_endian = 0;

    configure_info.private_data = (void *)&spi_master_param;
    ret = DeviceObtainBus(spi_sd_dev->spi_dev->haldev.owner_bus, &spi_sd_dev->spi_dev->haldev, spi_drv->drv_name, &configure_info);
    if (EOK != ret) {
        KPrintf("SdRead SD SPI obtain spi bus error!\n");
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ERROR;
    }

    /*Step2 : read SD block*/
    if (1 == block_num) {
        ret = SdReadSingleBlock(spi_sd_dev, id, read_buffer);
        if (EOK != ret) {
            KPrintf("SdRead SingleBlock error %d\n", ret);
            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);
            KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
            return 0;
        }
    } else {
        ret = SdReadMultiBlock(spi_sd_dev, id, read_buffer, block_num);
        if (EOK != ret) {
            KPrintf("SdRead MultiBlock error %d\n", ret);
            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);
            KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
            return 0;
        }
    }

    KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);

    return block_num;
}

uint32 SdWrite(void *dev, struct BusBlockWriteParam *write_param)
{
    NULL_PARAM_CHECK(dev);

    SpiSdDeviceType spi_sd_dev;
    HardwareDevType haldev = (struct HardwareDev *)dev;
    struct SpiHardwareDevice *sd_dev;

    sd_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
    spi_sd_dev = CONTAINER_OF(sd_dev, struct SpiSdDevice, sd_dev);

    uint32 id = write_param->pos;
    uint32 block_num = write_param->size;
    const uint8 *write_buffer = (uint8 *)write_param->buffer;

    if (0 == block_num) {
        KPrintf("SdWrite block_num is 0 just return\n");
        return block_num;
    }

    x_err_t ret = EOK;
    struct Driver *spi_drv = spi_sd_dev->spi_dev->haldev.owner_bus->owner_driver;

    /*Step1 : SD Card Obtain SPI  BUS*/
    struct BusConfigureInfo configure_info;
    struct SpiMasterParam spi_master_param;
    spi_master_param.spi_data_bit_width = 8;
    spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
    spi_master_param.spi_maxfrequency = spi_sd_dev->sd_param.sd_spi_maxfreq;
    spi_master_param.spi_data_endian = 0;

    configure_info.private_data = (void *)&spi_master_param;
    ret = DeviceObtainBus(spi_sd_dev->spi_dev->haldev.owner_bus, &spi_sd_dev->spi_dev->haldev, spi_drv->drv_name, &configure_info);
    if (EOK != ret) {
        KPrintf("SdWrite SD SPI obtain spi bus error!\n");
        KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
        return ERROR;
    }

    /*Step2 : write SD block*/
    if (1 == block_num) {
        ret = SdWriteSingleBlock(spi_sd_dev, id, write_buffer);
        if (EOK != ret) {
            KPrintf("SdWrite SingleBlock error %d\n", ret);
            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);
            KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
            return 0;
        }
    } else {
        ret = SdWriteMultiBlock(spi_sd_dev, id, write_buffer, block_num);
        if (EOK != ret) {
            KPrintf("SdWrite MultiBlock error %d\n", ret);
            /*pull up the cs pin*/
            SpiDevConfigureCs(&spi_sd_dev->spi_dev->haldev, 0, 1);
            KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
            return 0;
        }
    }

    KMutexAbandon(spi_sd_dev->spi_dev->haldev.owner_bus->bus_lock);
    return block_num;
}

static int SdControl(struct HardwareDev *dev, struct HalDevBlockParam *block_param)
{
    NULL_PARAM_CHECK(dev);

    if (OPER_BLK_GETGEOME == block_param->cmd) {
        block_param->dev_block.size_perbank = g_spi_sd_dev.sd_param.block_param.sector_bytes;
        block_param->dev_block.block_size = g_spi_sd_dev.sd_param.block_param.block_size;
        block_param->dev_block.bank_num = g_spi_sd_dev.sd_param.block_param.sector_num;
    }

    return EOK;
}

static const struct HalDevDone sd_done =
{
    .open = SdOpen,
    .close = SdClose,
    .write = SdWrite,
    .read = SdRead,
};

SpiSdDeviceType SpiSdInit(struct Bus *bus, const char *dev_name, const char *drv_name, const char *sd_name)
{
    NULL_PARAM_CHECK(dev_name);
    NULL_PARAM_CHECK(drv_name);
    NULL_PARAM_CHECK(sd_name);
    NULL_PARAM_CHECK(bus);

    x_err_t ret = EOK;
    SpiSdDeviceType spi_sd_dev = &g_spi_sd_dev;
    HardwareDevType haldev;

    memset(spi_sd_dev, 0, sizeof(struct SpiSdDevice));

    haldev = SpiDeviceFind(dev_name, TYPE_SPI_DEV);
    if (NONE == haldev) {
        KPrintf("SpiSdInit find spi haldev %s error! \n", dev_name);
        return NONE;
    }

    spi_sd_dev->spi_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
    if (NONE == spi_sd_dev->spi_dev) {
        KPrintf("SpiSdInit find spi sd device %s error! \n", dev_name);
        return NONE;
    }

    spi_sd_dev->sd_dev.spi_dev_flag = RET_TRUE;
    spi_sd_dev->sd_dev.haldev.dev_done = &sd_done;
    spi_sd_dev->sd_dev.haldev.dev_block_control = SdControl;

    spi_sd_dev->spi_dev->haldev.owner_bus->owner_driver = SpiDriverFind(drv_name, TYPE_SPI_DRV);
    if (NONE == spi_sd_dev->spi_dev->haldev.owner_bus->owner_driver) {
        KPrintf("SpiSdInit find spi driver %s error! \n", drv_name);
        return NONE;
    }

    ret = SpiDeviceRegister(&spi_sd_dev->sd_dev, NONE, sd_name);
    if (EOK != ret) {
        KPrintf("SpiSdInit SpiDeviceRegister device %s error %d\n", sd_name, ret);
        return NONE;
    }

    ret = SpiDeviceAttachToBus(sd_name, bus->bus_name);
    if (EOK != ret) {
        KPrintf("SpiSdInit SpiDeviceAttachToBus device %s error %d\n", sd_name, ret);
        return NONE;
    }

    return spi_sd_dev;
}
