SDHI_driver patch (mbedOS 5.11.5)

mbed-os-program/mbed-os/components/storage/blockdevice/COMPONENT_SD/SDHIBlockDevice.cpp

Committer:
tvendov
Date:
2019-03-18
Revision:
0:e1f465d87307

File content as of revision 0:e1f465d87307:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2012 ARM Limited
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
 
#if (defined(TARGET_VK_RZ_A1H) || defined(TARGET_VK_RZ_A1LU))
 
#include "SDHIBlockDevice.h"
#include "mbed_debug.h"
#include <errno.h>

#include "iodefine.h"
#include "PeripheralPins.h"

/* Required version: 5.6.1 and above */
#ifdef MBED_MAJOR_VERSION
#if (MBED_VERSION < MBED_ENCODE_VERSION(5,6,1))
#error "Incompatible mbed-os version detected! Required 5.5.4 and above"
#endif
#else
#warning "mbed-os version 5.6.1 or above required"
#endif



//#define SD_COMMAND_TIMEOUT                       5000   /*!< Timeout in ms for response */
//#define SD_CMD0_GO_IDLE_STATE_RETRIES            5      /*!< Number of retries for sending CMDO */
#define SD_CMD_TRACE                             0      /*!< 1 - Enable SD command tracing */

//#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK        -5001	/*!< operation would block */
#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED        -5002	/*!< unsupported operation */
#define SD_BLOCK_DEVICE_ERROR_PARAMETER          -5003	/*!< invalid parameter */
#define SD_BLOCK_DEVICE_ERROR_NO_INIT            -5004	/*!< uninitialized */
#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE          -5005	/*!< device is missing or not connected */
#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED    -5006	/*!< write protected */
#define SD_BLOCK_DEVICE_ERROR_UNUSABLE           -5007  /*!< unusable card */
#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE        -5008  /*!< No response from device */
#define SD_BLOCK_DEVICE_ERROR_CRC                -5009  /*!< CRC error */
#define SD_BLOCK_DEVICE_ERROR_ERASE              -5010  /*!< Erase error: reset/sequence */
#define SD_BLOCK_DEVICE_ERROR_WRITE              -5011  /*!< SPI Write error: !SPI_DATA_ACCEPTED */

#define BLOCK_SIZE_HC                            512    /*!< Block size supported for SD card is 512 bytes  */
#define WRITE_BL_PARTIAL                         0      /*!< Partial block write - Not supported */
//
// Types
#define SDCARD_NONE              0           /**< No card is present */
#define SDCARD_V1                1           /**< v1.x Standard Capacity */
#define SDCARD_V2                2           /**< v2.x Standard capacity SD card */
#define SDCARD_V2HC              3           /**< v2.x High capacity SD card */
#define CARD_UNKNOWN             4           /**< Unknown or unsupported card */

/* R3 Response : OCR Register */
#define OCR_HCS_CCS             (0x1 << 30)
#define OCR_LOW_VOLTAGE         (0x01 << 24)
#define OCR_3_3V                (0x1 << 20)

#define ESD_SECTOR_SIZE 		BLOCK_SIZE_HC

#define REG_CSD_HACK

#define CSD_CID_LENGTH        16

#define ARRAYSIZE(arr)	(size_t)(sizeof(arr)/sizeof(arr[0]))

static uint32_t _sd_workbuf[SD_SIZE_OF_INIT/ sizeof(uint32_t)] __attribute__ ((section ("NC_BSS")));
static uint32_t _sd_rw_buf[ESD_SECTOR_SIZE/sizeof(uint32_t)] __attribute__ ((section ("NC_BSS")));
//static uint8_t  _sectorBuff[ESD_SECTOR_SIZE] __attribute__ ((section ("NC_BSS")));


static uint32_t ext_bits(unsigned char *data, size_t datasize, unsigned int msb, unsigned int lsb) {
    uint32_t bits = 0;

    if ((datasize > 0) && (msb < (datasize<<3)))
    {
    	uint32_t size = 1 + msb - lsb;
    	for (uint32_t i = 0; i < size; i++)
    	{
    		uint32_t position = lsb + i;
    		int32_t byte = (datasize-1) - (position >> 3);
    		if( byte < 0 )
    			break;
    		uint32_t bit = position & 0x7;
    		uint32_t value = (data[byte] >> bit) & 1;
    		bits |= value << i;
    	}
    }
    return bits;
}

#if SDHI_DBG
const sderr_t SDHIBlockDevice::_sd_error_msg[]= {
	    {"SD_OK",                       0},        /* OK */
	    {"SD_ERR",                     -1},        /* general error */
	    {"SD_ERR_WP",                  -2},        /* write protect error */
	    {"SD_ERR_RO",                  -3},        /* read only error */
	    {"SD_ERR_RES_TOE",             -4},        /* response time out error */
	    {"SD_ERR_CARD_TOE",            -5},        /* card time out error */
	    {"SD_ERR_END_BIT",             -6},        /* end bit error */
	    {"SD_ERR_CRC",                 -7},        /* CRC error */
	    {"SD_ERR_CARD_RES",            -8},        /* card response error */
	    {"SD_ERR_HOST_TOE",            -9},        /* host time out error */
	    {"SD_ERR_CARD_ERASE",         -10},        /* card erase error */
	    {"SD_ERR_CARD_LOCK",          -11},        /* card lock error */
	    {"SD_ERR_CARD_UNLOCK",        -12},        /* card unlock error */
	    {"SD_ERR_HOST_CRC",           -13},        /* host CRC error */
	    {"SD_ERR_CARD_ECC",           -14},        /* card internal ECC error */
	    {"SD_ERR_CARD_CC",            -15},        /* card internal error */
	    {"SD_ERR_CARD_ERROR",         -16},        /* unknown card error */
	    {"SD_ERR_CARD_TYPE",          -17},        /* non support card type */
	    {"SD_ERR_NO_CARD",            -18},        /* no card */
	    {"SD_ERR_ILL_READ",           -19},        /* illegal buffer read */
	    {"SD_ERR_ILL_WRITE",          -20},        /* illegal buffer write */
	    {"SD_ERR_AKE_SEQ",            -21},        /* the sequence of authentication process */
	    {"SD_ERR_OVERWRITE",          -22},        /* CID/CSD overwrite error */
	/* 23-29 */
	    {"SD_ERR_CPU_IF",             -30},        /* target CPU interface function error  */
	    {"SD_ERR_STOP",               -31},        /* user stop */
	/* 32-49 */
	    {"SD_ERR_CSD_VER",            -50},        /* CSD register version error */
	    {"SD_ERR_SCR_VER",            -51},        /* SCR register version error */
	    {"SD_ERR_FILE_FORMAT",        -52},        /* CSD register file format error  */
	    {"SD_ERR_NOTSUP_CMD",         -53},        /* not supported command  */
	/* 54-59 */
	    {"SD_ERR_ILL_FUNC",           -60},        /* invalid function request error */
	    {"SD_ERR_IO_VERIFY",          -61},        /* direct write verify error */
	    {"SD_ERR_IO_CAPAB",           -62},        /* IO capability error */
	/* 63-69 */
	    {"SD_ERR_IFCOND_VER",         -70},        /* Interface condition version error */
	    {"SD_ERR_IFCOND_VOLT",        -71},        /* Interface condition voltage error */
	    {"SD_ERR_IFCOND_ECHO",        -72},        /* Interface condition echo back pattern error */
	/* 73-79 */
	    {"SD_ERR_OUT_OF_RANGE",       -80},        /* the argument was out of range */
	    {"SD_ERR_ADDRESS_ERROR",      -81},
	    {"SD_ERR_BLOCK_LEN_ERROR",    -82},
	    {"SD_ERR_ILLEGAL_COMMAND",    -83},
	    {"SD_ERR_RESERVED_ERROR18",   -84},
	    {"SD_ERR_RESERVED_ERROR17",   -85},
	    {"SD_ERR_CMD_ERROR",          -86},
	    {"SD_ERR_CBSY_ERROR",         -87},
	    {"SD_ERR_NO_RESP_ERROR",      -88},
	/* 89 */
	/* 90-95 */
	    {"SD_ERR_ERROR",              -96},
	    {"SD_ERR_FUNCTION_NUMBER",    -97},
	    {"SD_ERR_COM_CRC_ERROR",      -98},
	    {"SD_ERR_INTERNAL",           -99},        /* driver software internal error */
};

#endif

SDHIBlockDevice::SDHIBlockDevice(uint32_t sdport)
{
	_init_ref_count = 0;
	Initialize(sdport);
//    for( uint32_t n=0; n < ARRAYSIZE(_sd_error_msg); n++ )
//    {
//    	_sd_err_map[_sd_error_msg[n].errorno] = _sd_error_msg[n].msg;
//    }
//
//    if ( sdport < SDHI_COUNT )
//    {
//    	_sd_channel = sdport;
//    	_regbase = (uint32_t)((_sd_channel == 0ul) ? &SDHI0 : &SDHI1);
//
//    	_card_type = SDCARD_NONE;
//
//    	// Set default to 100kHz for initialisation and 1MHz for data transfer
//    	_init_sck = 100000;
//    	_transfer_sck = hz;
//
//    	// Only HC block size is supported.
//    	_block_size = BLOCK_SIZE_HC;
//    	_erase_size = BLOCK_SIZE_HC;
//    	_mtx_lock = false;
//
//    	int32_t sd_err = sd_init( _sd_channel, _regbase, &_sd_workbuf[0], SD_CD_SOCKET );
//    	if ( sd_err != SD_OK)
//    	{
//    		_error(sd_err);
////    		return SD_BLOCK_DEVICE_ERROR_NO_DEVICE;
//    	}
//
//    	void *rw_buff = (void *)&_sd_rw_buf[0];
//
//    	sd_err = sd_set_buffer( _sd_channel, rw_buff, (unsigned long)sizeof(_sd_rw_buf) );
//    	if ( sd_err != SD_OK )
//    	{
//    		_error(sd_err);
//    	}
//
//    }
//    else
//    {
//    	_sd_channel = -1;
//    	_regbase = 0ul;
//
//    }
}

SDHIBlockDevice::SDHIBlockDevice(PinName sd_CLK, PinName sd_CMD, PinName sd_CD, PinName sd_WP,
		                         PinName sd_D0,	PinName sd_D1, PinName sd_D2, PinName sd_D3 )
{
	_init_ref_count = 0;

    uint32_t sd_wp  = pinmap_peripheral(sd_WP, PinMap_SDHI_WP);
    uint32_t sd_cd  = pinmap_peripheral(sd_CD, PinMap_SDHI_CD);
    uint32_t sd_clk = pinmap_peripheral(sd_CLK, PinMap_SDHI_CLK);
    uint32_t sd_cmd = pinmap_peripheral(sd_CMD, PinMap_SDHI_CMD);
    uint32_t sd_d0  = pinmap_peripheral(sd_D0, PinMap_SDHI_D0);
    uint32_t sd_d1  = pinmap_peripheral(sd_D1, PinMap_SDHI_D1);
    uint32_t sd_d2  = pinmap_peripheral(sd_D2, PinMap_SDHI_D2);
    uint32_t sd_d3  = pinmap_peripheral(sd_D3, PinMap_SDHI_D3);

    uint32_t sd_cntl_1 = pinmap_merge(sd_wp, sd_cd);
    uint32_t sd_cntl_2 = pinmap_merge(sd_clk, sd_cmd);
    uint32_t sd_cntl = pinmap_merge(sd_cntl_1, sd_cntl_2);

    uint32_t sd_data_1 = pinmap_merge(sd_d0, sd_d1);
    uint32_t sd_data_2 = pinmap_merge(sd_d2, sd_d3);
    uint32_t sd_data = pinmap_merge(sd_data_1, sd_data_2);

    uint32_t sdport = pinmap_merge(sd_cntl, sd_data);

    MBED_ASSERT((int)sdport != NC);

    Initialize(sdport);
}



SDHIBlockDevice::~SDHIBlockDevice()
{
    if (_is_initialized) {
        deinit();
    }
}

void SDHIBlockDevice::Initialize( uint32_t sdport )
{
#if SDHI_DBG
    for( uint32_t n=0; n < ARRAYSIZE(_sd_error_msg); n++ )
    {
    	_sd_err_map[_sd_error_msg[n].errorno] = _sd_error_msg[n].msg;
    }
#endif
    _sectors = 0;
    _is_initialized = 0;
    if ( sdport < SDHI_COUNT )
    {
    	_sd_channel = sdport;
    	_regbase = (uint32_t)((_sd_channel == SDHI_0) ? &SDHI0 : &SDHI1);

    	_card_type = SDCARD_NONE;

    	// Only HC block size is supported.
    	_block_size = BLOCK_SIZE_HC;
    	_erase_size = BLOCK_SIZE_HC;

    	int32_t sd_err = sd_init( _sd_channel, _regbase, &_sd_workbuf[0], SD_CD_SOCKET );
    	if ( sd_err != SD_OK)
    	{
    		_error(sd_err);
    	}

    	void *rw_buff = (void *)&_sd_rw_buf[0];

    	sd_err = sd_set_buffer( _sd_channel, rw_buff, (unsigned long)sizeof(_sd_rw_buf) );
    	if ( sd_err != SD_OK )
    	{
    		_error(sd_err);
    	}
    }
    else
    {
    	_sd_channel = -1;
    	_regbase = 0ul;

    }

}

int SDHIBlockDevice::_initialise_card()
{
    // Detail debugging is for commands
    _dbg = SDHI_DBG ? SD_CMD_TRACE : 0;

    int32_t status = BD_ERROR_OK;

    int32_t sd_err;

    if( _regbase )
    {
    	sd_err = sd_mount(_sd_channel, SDCFG_DRIVER_MODE, SD_VOLT_3_3);

    	if ( sd_err != SD_OK )
    	{
    		_error(sd_err);
    		return SD_BLOCK_DEVICE_ERROR_UNUSABLE;
    	}
        uint8_t    card_type;
	    uint8_t    card_speed;
	    uint8_t    card_capa;

		sd_err=sd_get_type(_sd_channel, &card_type, &card_speed, &card_capa);
        if( sd_err != SD_OK)
        {
        	return _error(sd_err);
        }

        if( (card_type & SD_MEDIA_SD) != SD_MEDIA_SD )
        {
    		return SD_BLOCK_DEVICE_ERROR_UNUSABLE;
        }

		uint32_t regOCR;
		uint8_t regCID[CSD_CID_LENGTH];
		uint8_t regCSD[CSD_CID_LENGTH];
		uint8_t regDSR[2];
		uint8_t regSCR[8];

		sd_err = sd_get_reg(_sd_channel, (uint8_t *)&regOCR, regCID, regCSD, regDSR, regSCR);
		if (sd_err != SD_OK)
		{
			return _error(sd_err);
		}
		regOCR = __REV(regOCR);
		// Check if card supports voltage range: 3.3V
		if (!(regOCR & OCR_3_3V)) {
			_card_type = CARD_UNKNOWN;
			status = SD_BLOCK_DEVICE_ERROR_UNUSABLE;
			return status;
		}
    }
    else
    {
    	status = SD_BLOCK_DEVICE_ERROR_NO_INIT;
    }

    return status;
}


int SDHIBlockDevice::init()
{
	vMutex l(&_mutex);

    if(!_is_initialized)
        _init_ref_count = 0;

    _init_ref_count++;

    if(_init_ref_count != 1)
        return BD_ERROR_OK;

    int err = _initialise_card();
    _is_initialized = (err == BD_ERROR_OK);
    if (!_is_initialized) {
        debug_if(SDHI_DBG, "Fail to initialize card\n");
        return err;
    }
    debug_if(SDHI_DBG, "init card = %d\r\n", _is_initialized);
    _sectors = _sd_sectors();

    if (0 == _sectors) {
        return BD_ERROR_DEVICE_ERROR;
    }

    return BD_ERROR_OK;
}

int SDHIBlockDevice::deinit()
{
	vMutex l(&_mutex);

    if(!_is_initialized)
        _init_ref_count = 0;

    _init_ref_count--; //!!!

    if(_init_ref_count)
        return BD_ERROR_OK;

    _sectors = 0;
    if ( _is_initialized )
    {
    	sd_unmount(_sd_channel);
    	debug_if(SDHI_DBG, "card deinited![%d]\r\n", _is_initialized);
    	_is_initialized = false;
    }
    return 0;
}


int SDHIBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
{
    if (!is_valid_program(addr, size)) {
        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
    }

    vMutex l(&_mutex);

    if (!_is_initialized) {
        return SD_BLOCK_DEVICE_ERROR_NO_INIT;
    }

    uint8_t* buffer = const_cast<uint8_t*>(static_cast<const uint8_t*>(b));
	int status = BD_ERROR_OK;

	// Get block count
	bd_addr_t blockCnt = size / _block_size;

	addr = addr / _block_size;

	// Send command to perform write operation
	int32_t sd_err = sd_write_sect( _sd_channel, buffer, addr, blockCnt, SD_WRITE_OVERWRITE);

	if (sd_err != SD_OK)
	{
		_error(sd_err);
		status = SD_BLOCK_DEVICE_ERROR_WRITE;
	}

	return status;
}

int SDHIBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
{
    if (!is_valid_read(addr, size)) {
        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
    }

    vMutex l(&_mutex);

    if (!_is_initialized) {
        return SD_BLOCK_DEVICE_ERROR_NO_INIT;
    }
	uint8_t *buffer = static_cast<uint8_t*>(b);
	int status = BD_ERROR_OK;
	bd_addr_t blockCnt =  size / _block_size;

	addr = addr / _block_size;

	int32_t sd_err = sd_read_sect(_sd_channel, buffer, addr, blockCnt);

	if (sd_err != SD_OK)
	{
		_error(sd_err);
		status = SD_BLOCK_DEVICE_ERROR_NO_RESPONSE;
	}

	return status;
}

int SDHIBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
    return 0;
}


bool SDHIBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size)
{
    return (
        addr % _erase_size == 0 &&
        size % _erase_size == 0 &&
        addr + size <= this->size());
}

int SDHIBlockDevice::trim(bd_addr_t addr, bd_size_t size)
{
    if (!_is_valid_trim(addr, size)) {
        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
    }

	vMutex l(&_mutex);

    if (!_is_initialized) {
        return SD_BLOCK_DEVICE_ERROR_NO_INIT;
    }
    int status = BD_ERROR_OK;

    size -= _block_size;
    // SDSC Card (CCS=0) uses byte unit address
    // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit)
    if (SDCARD_V2HC == _card_type) {
        size = size / _block_size;
        addr = addr / _block_size;
    }

    return status;
}

bd_size_t SDHIBlockDevice::get_read_size() const
{
    return _block_size;
}

bd_size_t SDHIBlockDevice::get_program_size() const
{
    return _block_size;
}

/*
bd_size_t SDHIBlockDevice::get_erase_size() const
{
    return _block_size;
}
*/

bd_size_t SDHIBlockDevice::size() const
{
    return _block_size*_sectors;
}

void SDHIBlockDevice::debug(bool dbg)
{
    _dbg = dbg;
}

const char *SDHIBlockDevice::get_type() const
{
	return "RZ-SDHI";
}

// PRIVATE FUNCTIONS

bd_size_t SDHIBlockDevice::_sd_sectors() {
    uint32_t c_size, c_size_mult, read_bl_len;
    uint32_t block_len, mult, blocknr;
    uint32_t hc_c_size;
    bd_size_t blocks = 0, capacity = 0;
    uint8_t csd[CSD_CID_LENGTH];

    int32_t sd_err = sd_get_reg(_sd_channel, NULL, NULL, csd, NULL, NULL);
    if ( sd_err != SD_OK )
    {
        debug_if(SDHI_DBG, "Couldn't read csd response from disk\r\n");
        _error(sd_err);
        return 0;
    }
    for(int i = 0; i < (CSD_CID_LENGTH-1); i++)
    {
    	csd[i] = csd[i+1];
    }

    debug_if(SDHI_DBG,"CSD is ");
    for(unsigned int i = 0; i < sizeof(csd); i++)
    {
    	debug_if(SDHI_DBG, "%02X ", csd[i]);
    }
    debug_if(SDHI_DBG,"\r\n");

    // csd_structure : csd[127:126]
    int csd_structure = ext_bits(csd, CSD_CID_LENGTH, 127, 126);
    switch (csd_structure) {
        case 0:
            c_size = ext_bits(csd, CSD_CID_LENGTH, 73, 62);              // c_size        : csd[73:62]
            c_size_mult = ext_bits(csd, CSD_CID_LENGTH, 49, 47);         // c_size_mult   : csd[49:47]
            read_bl_len = ext_bits(csd, CSD_CID_LENGTH, 83, 80);         // read_bl_len   : csd[83:80] - the *maximum* read block length
            block_len = 1 << read_bl_len;                // BLOCK_LEN = 2^READ_BL_LEN
            mult = 1 << (c_size_mult + 2);               // MULT = 2^C_SIZE_MULT+2 (C_SIZE_MULT < 8)
            blocknr = (c_size + 1) * mult;               // BLOCKNR = (C_SIZE+1) * MULT
            capacity = blocknr * block_len;              // memory capacity = BLOCKNR * BLOCK_LEN
            blocks = capacity / _block_size;
            debug_if(SDHI_DBG, "Standard Capacity: c_size: %lu\r\n", c_size);
            debug_if(SDHI_DBG, "Sectors: 0x%llx : %llu\r\n", blocks, blocks);
            debug_if(SDHI_DBG, "Capacity: 0x%llx : %llu MB\r\n", capacity, (capacity/(1024U*1024U)));

            // ERASE_BLK_EN = 1: Erase in multiple of 512 bytes supported
            if (ext_bits(csd, CSD_CID_LENGTH, 46, 46)) {
                _erase_size = BLOCK_SIZE_HC;
            } else {
                // ERASE_BLK_EN = 1: Erase in multiple of SECTOR_SIZE supported
                _erase_size = BLOCK_SIZE_HC * (ext_bits(csd, CSD_CID_LENGTH, 45, 39) + 1);
            }
            break;

        case 1:
            hc_c_size = ext_bits(csd, CSD_CID_LENGTH, 69, 48);            // device size : C_SIZE : [69:48]
            blocks = (hc_c_size+1) << 10;                 // block count = C_SIZE+1) * 1K byte (512B is block size)
            debug_if(SDHI_DBG, "SDHC/SDXC Card: hc_c_size: %lu\r\n", hc_c_size);
            debug_if(SDHI_DBG, "Sectors: 0x%llx : %llu\r\n", blocks, blocks);
            debug_if(SDHI_DBG, "Capacity: %llu MB\r\n", (blocks/(2048U)));
            // ERASE_BLK_EN is fixed to 1, which means host can erase one or multiple of 512 bytes.
            _erase_size = BLOCK_SIZE_HC;
            break;

        default:
            debug_if(SDHI_DBG, "CSD struct unsupported\r\n");
            return 0;
    };
    return blocks;
}

const char * SDHIBlockDevice::_sderr_msg(int32_t errorno)
{
#if SDHI_DBG
	map<int32_t, const char *>::iterator it = _sd_err_map.find(errorno);

	if ( it != _sd_err_map.end() )
		return it->second;
	else
		return "SD UNKNWON ERROR NO\n";
#else
	return (const char *)0;
#endif
}

int SDHIBlockDevice::_error(int32_t errcode)
{
	int32_t sd_err = errcode;
	if(_sd_channel >= 0 && _sd_channel < SDHI_COUNT )
	{
		int32_t err = sd_get_error(_sd_channel);
		if ( err != SD_OK)
			sd_err = err;
		debug_if(SDHI_DBG, _sderr_msg(sd_err));
	}
	return sd_err;
}

#endif