X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=bertos%2Fdrv%2Fsd.c;h=90498296277ff8173e06988dc9112e2faf8fb760;hb=f57ced5005f3378b0ba52cce00b14a7976363ae3;hp=364c8d485ccc396771e36e5bfd498a05d8870010;hpb=b46f64914c62fbb0297728280478681659469654;p=bertos.git diff --git a/bertos/drv/sd.c b/bertos/drv/sd.c index 364c8d48..90498296 100644 --- a/bertos/drv/sd.c +++ b/bertos/drv/sd.c @@ -38,10 +38,15 @@ #include "sd.h" #include "hw/hw_sd.h" #include +#include #include #include +#include "cfg/cfg_sd.h" + +#define LOG_LEVEL SD_LOG_LEVEL +#define LOG_FORMAT SD_LOG_FORMAT #include #include @@ -61,39 +66,30 @@ typedef struct CardCSD #define SD_IN_IDLE 0x01 #define SD_STARTTOKEN 0xFE -#define TIMEOUT_NAC 256 - +#define TIMEOUT_NAC 16384 #define SD_DEFAULT_BLOCKLEN 512 -/** - * SPI communication channel. - */ -static KFile *fd; - -/** - * Current SD status. - */ -static bool sd_status; - #define SD_BUSY_TIMEOUT ms_to_ticks(200) -static bool sd_select(bool state) +static bool sd_select(Sd *sd, bool state) { + KFile *fd = sd->ch; + if (state) { + SD_CS_ON(); + ticks_t start = timer_clock(); do { - SD_CS_ON(); if (kfile_getc(fd) == 0xff) return true; - SD_CS_OFF(); - kfile_putc(0xff, fd); - kfile_flush(fd); + cpu_relax(); } while (timer_clock() - start < SD_BUSY_TIMEOUT); + SD_CS_OFF(); LOG_ERR("sd_select timeout\n"); return false; } @@ -106,22 +102,23 @@ static bool sd_select(bool state) } } -static int16_t sd_waitR1(void) +static int16_t sd_waitR1(Sd *sd) { uint8_t datain; for (int i = 0; i < TIMEOUT_NAC; i++) { - datain = kfile_getc(fd); - if (datain != 0xff) - return (int16_t)datain; + datain = kfile_getc(sd->ch); + if (datain != 0xff) + return (int16_t)datain; } LOG_ERR("Timeout waiting R1\n"); return EOF; } -static int16_t sd_sendCommand(uint8_t cmd, uint32_t param, uint8_t crc) +static int16_t sd_sendCommand(Sd *sd, uint8_t cmd, uint32_t param, uint8_t crc) { + KFile *fd = sd->ch; /* The 7th bit of command must be a 1 */ kfile_putc(cmd | 0x40, fd); @@ -133,15 +130,16 @@ static int16_t sd_sendCommand(uint8_t cmd, uint32_t param, uint8_t crc) kfile_putc(crc, fd); - return sd_waitR1(); + return sd_waitR1(sd); } - -static bool sd_getBlock(void *buf, size_t len) +static bool sd_getBlock(Sd *sd, void *buf, size_t len) { uint8_t token; uint16_t crc; + KFile *fd = sd->ch; + for (int i = 0; i < TIMEOUT_NAC; i++) { token = kfile_getc(fd); @@ -171,10 +169,10 @@ static bool sd_getBlock(void *buf, size_t len) return false; } -#define SD_SELECT() \ +#define SD_SELECT(sd) \ do \ { \ - if (!sd_select(true)) \ + if (!sd_select((sd), true)) \ { \ LOG_ERR("%s failed, card busy\n", __func__); \ return EOF; \ @@ -184,37 +182,44 @@ while (0) #define SD_SETBLOCKLEN 0x50 -static int16_t sd_setBlockLen(uint32_t newlen) +static int16_t sd_setBlockLen(Sd *sd, uint32_t newlen) { - SD_SELECT(); + SD_SELECT(sd); - int16_t r1 = sd_sendCommand(SD_SETBLOCKLEN, newlen, 0); + sd->r1 = sd_sendCommand(sd, SD_SETBLOCKLEN, newlen, 0); - sd_select(false); - return r1; + sd_select(sd, false); + return sd->r1; } #define SD_SEND_CSD 0x49 -static int16_t sd_getCSD(CardCSD *csd) +static int16_t sd_getCSD(Sd *sd, CardCSD *csd) { - SD_SELECT(); + SD_SELECT(sd); - int16_t r1 = sd_sendCommand(SD_SEND_CSD, 0, 0); + int16_t r1 = sd_sendCommand(sd, SD_SEND_CSD, 0, 0); if (r1) { - LOG_ERR("send_csd failed: %04X\n", r1); - sd_select(false); + LOG_ERR("send_csd failed: %04X\n", sd->r1); + sd_select(sd, false); return r1; } uint8_t buf[16]; - bool res = sd_getBlock(buf, sizeof(buf)); - sd_select(false); + bool res = sd_getBlock(sd, buf, sizeof(buf)); + sd_select(sd, false); if (res) { + #if LOG_LEVEL >= LOG_LVL_INFO + LOG_INFO("CSD: ["); + for (int i = 0; i < 16; i++) + kprintf("%02X ", buf[i]); + kprintf("]\n"); + #endif + uint16_t mult = (1L << ((((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7)) + 2)); uint16_t c_size = (((uint16_t)(buf[6] & 0x03)) << 10) | (((uint16_t)buf[7]) << 2) | (((uint16_t)(buf[8] & 0xC0)) >> 6); @@ -233,44 +238,73 @@ static int16_t sd_getCSD(CardCSD *csd) #define SD_READ_SINGLEBLOCK 0x51 -static int16_t sd_readBlock(void *buf, uint32_t addr) +static size_t sd_readDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size) { - SD_SELECT(); + Sd *sd = SD_CAST(b); + LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size); + + if (sd->tranfer_len != size) + { + if ((sd->r1 = sd_setBlockLen(sd, size))) + { + LOG_ERR("setBlockLen failed: %04X\n", sd->r1); + return 0; + } + sd->tranfer_len = size; + } - int16_t r1 = sd_sendCommand(SD_READ_SINGLEBLOCK, addr, 0); + SD_SELECT(sd); - if (r1) + sd->r1 = sd_sendCommand(sd, SD_READ_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN + offset, 0); + + if (sd->r1) { - LOG_ERR("read single block failed: %04X\n", r1); - sd_select(false); - return r1; + LOG_ERR("read single block failed: %04X\n", sd->r1); + sd_select(sd, false); + return 0; } - bool res = sd_getBlock(buf, SD_DEFAULT_BLOCKLEN); - sd_select(false); + bool res = sd_getBlock(sd, buf, size); + sd_select(sd, false); if (!res) { LOG_ERR("read single block failed reading data\n"); - return EOF; + return 0; } else - return 0; + return size; } #define SD_WRITE_SINGLEBLOCK 0x58 #define SD_DATA_ACCEPTED 0x05 -static int16_t sd_writeBlock(const void *buf, uint32_t addr) +static size_t sd_writeDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size) { - SD_SELECT(); + Sd *sd = SD_CAST(b); + KFile *fd = sd->ch; + ASSERT(offset == 0); + ASSERT(size == SD_DEFAULT_BLOCKLEN); + + LOG_INFO("writing block %ld\n", idx); + if (sd->tranfer_len != SD_DEFAULT_BLOCKLEN) + { + if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN))) + { + LOG_ERR("setBlockLen failed: %04X\n", sd->r1); + return 0; + } + sd->tranfer_len = SD_DEFAULT_BLOCKLEN; + } - int16_t r1 = sd_sendCommand(SD_WRITE_SINGLEBLOCK, addr, 0); + SD_SELECT(sd); - if (r1) + sd->r1 = sd_sendCommand(sd, SD_WRITE_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN, 0); + + if (sd->r1) { - LOG_ERR("write single block failed: %04X\n", r1); - sd_select(false); - return r1; + LOG_ERR("write single block failed: %04X\n", sd->r1); + sd_select(sd, false); + return 0; } kfile_putc(SD_STARTTOKEN, fd); @@ -278,28 +312,36 @@ static int16_t sd_writeBlock(const void *buf, uint32_t addr) /* send fake crc */ kfile_putc(0, fd); kfile_putc(0, fd); - uint8_t dataresp = (kfile_getc(fd) & 0x1F); - sd_select(false); - // FIXME: sometimes dataresp is 0, find out why. - if (dataresp != SD_DATA_ACCEPTED) + uint8_t dataresp = kfile_getc(fd); + sd_select(sd, false); + + if ((dataresp & 0x1f) != SD_DATA_ACCEPTED) { - LOG_ERR("write single block failed: %02X\n", dataresp); + LOG_ERR("write block %ld failed: %02X\n", idx, dataresp); return EOF; } - else - return 0; -} + return SD_DEFAULT_BLOCKLEN; +} -bool sd_test(void) +void sd_writeTest(Sd *sd) { - CardCSD csd; - sd_getCSD(&csd); + uint8_t buf[SD_DEFAULT_BLOCKLEN]; + memset(buf, 0, sizeof(buf)); + + for (block_idx_t i = 0; i < sd->b.blk_cnt; i++) + { + LOG_INFO("writing block %ld: %s\n", i, (sd_writeDirect(&sd->b, i, buf, 0, SD_DEFAULT_BLOCKLEN) == SD_DEFAULT_BLOCKLEN) ? "OK" : "FAIL"); + } +} + +bool sd_test(Sd *sd) +{ uint8_t buf[SD_DEFAULT_BLOCKLEN]; - if (sd_readBlock(buf, 0) != 0) + if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size) return false; kputchar('\n'); @@ -311,15 +353,15 @@ bool sd_test(void) kputchar('\n'); } - if (sd_writeBlock(buf, 0) != 0) + if (sd_writeDirect(&sd->b, 0, buf, 0, SD_DEFAULT_BLOCKLEN) != SD_DEFAULT_BLOCKLEN) return false; memset(buf, 0, sizeof(buf)); - if (sd_readBlock(buf, 0) != 0) + if (sd_readDirect(&sd->b, 0, buf, 0, sd->b.blk_size) != sd->b.blk_size) return false; kputchar('\n'); - for (int i = 0; i < SD_DEFAULT_BLOCKLEN; i++) + for (block_idx_t i = 0; i < sd->b.blk_size; i++) { kprintf("%02X ", buf[i]); buf[i] = i; @@ -330,21 +372,57 @@ bool sd_test(void) return true; } +static int sd_error(KBlock *b) +{ + Sd *sd = SD_CAST(b); + return sd->r1; +} + +static void sd_clearerr(KBlock *b) +{ + Sd *sd = SD_CAST(b); + sd->r1 = 0; +} + +static const KBlockVTable sd_unbuffered_vt = +{ + .readDirect = sd_readDirect, + .writeDirect = sd_writeDirect, + + .error = sd_error, + .clearerr = sd_clearerr, +}; + +static const KBlockVTable sd_buffered_vt = +{ + .readDirect = sd_readDirect, + .writeDirect = sd_writeDirect, + + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, + + .error = sd_error, + .clearerr = sd_clearerr, +}; + #define SD_GO_IDLE_STATE 0x40 #define SD_GO_IDLE_STATE_CRC 0x95 #define SD_SEND_OP_COND 0x41 #define SD_SEND_OP_COND_CRC 0xF9 -#define SD_START_DELAY ms_to_ticks(10) -#define SD_INIT_TIMEOUT ms_to_ticks(1000) +#define SD_START_DELAY 10 +#define SD_INIT_TIMEOUT 1000 #define SD_IDLE_RETRIES 4 -bool sd_init(KFile *_fd) +static bool sd_blockInit(Sd *sd, KFile *ch) { - uint16_t r1; - - ASSERT(_fd); - fd = _fd; + ASSERT(sd); + ASSERT(ch); + memset(sd, 0, sizeof(*sd)); + DB(sd->b.priv.type = KBT_SD); + sd->ch = ch; SD_CS_INIT(); SD_CS_OFF(); @@ -354,22 +432,22 @@ bool sd_init(KFile *_fd) /* Give 80 clk pulses to wake up the card */ for (int i = 0; i < 10; i++) - kfile_putc(0xff, fd); - kfile_flush(fd); + kfile_putc(0xff, ch); + kfile_flush(ch); for (int i = 0; i < SD_IDLE_RETRIES; i++) { - SD_SELECT(); - r1 = sd_sendCommand(SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC); - sd_select(false); + SD_SELECT(sd); + sd->r1 = sd_sendCommand(sd, SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC); + sd_select(sd, false); - if (r1 == SD_IN_IDLE) + if (sd->r1 == SD_IN_IDLE) break; } - if (r1 != SD_IN_IDLE) + if (sd->r1 != SD_IN_IDLE) { - LOG_ERR("go_idle_state failed: %04X\n", r1); + LOG_ERR("go_idle_state failed: %04X\n", sd->r1); return false; } @@ -378,120 +456,413 @@ bool sd_init(KFile *_fd) /* Wait for card to start */ do { - SD_SELECT(); - r1 = sd_sendCommand(SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC); - sd_select(false); + SD_SELECT(sd); + sd->r1 = sd_sendCommand(sd, SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC); + sd_select(sd, false); cpu_relax(); } - while (r1 != 0 && timer_clock() - start < SD_INIT_TIMEOUT); + while (sd->r1 != 0 && timer_clock() - start < SD_INIT_TIMEOUT); - if (r1) + if (sd->r1) { - LOG_ERR("send_op_cond failed: %04X\n", r1); + LOG_ERR("send_op_cond failed: %04X\n", sd->r1); return false; } - r1 = sd_setBlockLen(SD_DEFAULT_BLOCKLEN); + sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN); + sd->tranfer_len = SD_DEFAULT_BLOCKLEN; - if (r1) + if (sd->r1) { - LOG_ERR("setBlockLen failed: %04X\n", r1); + LOG_ERR("setBlockLen failed: %04X\n", sd->r1); return false; } - sd_status = !r1; - return sd_status; + /* Avoid warning for uninitialized csd use (gcc bug?) */ + CardCSD csd = csd; + + sd->r1 = sd_getCSD(sd, &csd); + + if (sd->r1) + { + LOG_ERR("getCSD failed: %04X\n", sd->r1); + return false; + } + + sd->b.blk_size = SD_DEFAULT_BLOCKLEN; + sd->b.blk_cnt = csd.block_num * (csd.block_len / SD_DEFAULT_BLOCKLEN); + LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt); + +#if CONFIG_SD_AUTOASSIGN_FAT + disk_assignDrive(&sd->b, 0); +#endif + + return true; } -DSTATUS sd_disk_initialize(BYTE drv) +#if CPU_CM3_SAM3X8 + +#include + +/* SD commands type argument response */ + /* class 0 */ +/* This is basically the same command as for MMC with some quirks. */ +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ +#define SD_SWITCH_VOLTAGE 11 /* ac R1 */ + + /* class 10 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ + + /* class 5 */ +#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */ + + /* Application commands */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SD_STATUS 13 /* adtc R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* OCR bit definitions */ +#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ +#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ +#define SD_OCR_XPC (1 << 28) /* SDXC power control */ + +/* + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ + +/* + * SD_SEND_IF_COND argument format: + * + * [31:12] Reserved (0) + * [11:8] Host Voltage Supply Flags + * [7:0] Check Pattern (0xAA) + */ + +/* + * SCR field definitions + */ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ + +#define UNSTUFF_BITS(resp, start, size) \ + ({ \ + const uint32_t __size = size; \ + const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1; \ + const uint32_t __off = 3 - ((start) / 32); \ + const uint32_t __shft = (start) & 31; \ + uint32_t __res; \ + \ + __res = resp[__off] >> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) % 32); \ + __res & __mask; \ + }) + + +#define BCD_TO_INT_32BIT(bcd) ((uint32_t )((bcd) & 0xf) * 1 + \ + (((bcd) >> 4) & 0xf) * 10 + \ + (((bcd) >> 8) & 0xf) * 100 + \ + (((bcd) >> 12) & 0xf) * 1000 + \ + (((bcd) >> 16) & 0xf) * 10000 + \ + (((bcd) >> 20) & 0xf) * 100000 + \ + (((bcd) >> 24) & 0xf) * 1000000 + \ + (((bcd) >> 28) & 0xf) * 10000000) \ + + +static void dump(uint32_t *r, size_t len) { - return sd_disk_status(drv); + ASSERT(r); + kputs("r [ "); + for (size_t i = 0; i < len; i++) + kprintf("%lx ", r[i]); + kputs("]\n"); } -DSTATUS sd_disk_status(BYTE drv) + +int sd_decode_csd(SDcsd *csd, uint32_t *resp, size_t len) { - ASSERT(!drv); + ASSERT(csd); + ASSERT(resp); + ASSERT(len >= 4); - if (sd_status) - return RES_OK; - else - return STA_NOINIT; -} + csd->structure = UNSTUFF_BITS(resp, 126, 2); + csd->ccc = UNSTUFF_BITS(resp, 84, 12); -DRESULT sd_disk_read(BYTE drv, BYTE* buf, DWORD sector, BYTE count) -{ - ASSERT(!drv); + if (csd->structure == 0) + { + kprintf("csize %ld\n", UNSTUFF_BITS(resp, 62, 12)); + kprintf("csize_mul %ld\n", UNSTUFF_BITS(resp, 47, 3)); + kprintf("bit read %ld %ld\n", csd->read_blk_bits = UNSTUFF_BITS(resp, 80, 4), csd->read_blk_bits); + + // (C_size + 1) x 2^(C_SIZE_MUL+2) + csd->blk_num = (1 + UNSTUFF_BITS(resp, 62, 12)) << (UNSTUFF_BITS(resp, 47, 3) + 2); + + csd->read_blk_bits = UNSTUFF_BITS(resp, 80, 4); + csd->write_blk_bits = UNSTUFF_BITS(resp, 22, 4); + + csd->blk_len = 1 << csd->read_blk_bits; + csd->capacity = csd->blk_num * csd->blk_len; + + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); - if (!sd_status) - return RES_NOTRDY; + if (UNSTUFF_BITS(resp, 46, 1)) + { + csd->erase_size = 1; + } + else if(csd->write_blk_bits >= 9) + { + csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1; + csd->erase_size <<= csd->write_blk_bits - 9; + } - while (count--) + return 0; + } + else if (csd->structure == 1) { - if (sd_readBlock(buf, sector * SD_DEFAULT_BLOCKLEN)) - return RES_ERROR; - buf += SD_DEFAULT_BLOCKLEN; - sector++; + kprintf("csize %ld\n", UNSTUFF_BITS(resp, 48, 22)); + csd->capacity = (1 + UNSTUFF_BITS(resp, 48, 22)) << 10; + + csd->write_blk_bits = 9; + csd->write_partial = 0; + csd->write_misalign = 0; + + csd->read_blk_bits = 9; + csd->read_partial = 0; + csd->read_misalign = 0; + + csd->erase_size = 1; + // the block size if fixed to 512kb + csd->blk_len = (1 << csd->write_blk_bits) << 10; + + return 0; } - return RES_OK; + else + { + kprintf("Unrecognised CSD structure version %d\n", csd->structure); + return -1; + } + + return 0; } -DRESULT sd_disk_write(BYTE drv, const BYTE* buf, DWORD sector, BYTE count) + +void sd_dump_csd(SDcsd *csd) { - ASSERT(!drv); + ASSERT(csd); + + kprintf("VERSION: %d.0\n", csd->structure ? 2 : 1); + kprintf("CARD COMMAND CLASS: %d\n", csd->ccc); + kprintf("WRITE BLK LEN BITS: %ld\n", csd->write_blk_bits); + kprintf("READ BLK LEN BITS: %ld\n", csd->read_blk_bits); + kprintf("ERASE SIZE: %ld\n", csd->erase_size); + kprintf("BLK NUM: %ld\n", csd->blk_num); + kprintf("BLK LEN: %ld\n", csd->blk_len); + kprintf("CAPACITY %ld\n", csd->capacity); + kprintf("FLAG Write: WP %d, W MISALIGN %d\n", csd->write_partial, csd->write_misalign); + kprintf("FLAG Read: RP %d, R MISALIGN %d\n", csd->read_partial, csd->read_misalign); + +} - if (!sd_status) - return RES_NOTRDY; - while (count--) - { - if (sd_writeBlock(buf, sector * SD_DEFAULT_BLOCKLEN)) - return RES_ERROR; - buf += SD_DEFAULT_BLOCKLEN; - sector++; - } - return RES_OK; +void sd_decode_cid(SDcid *cid, uint32_t *resp, size_t len) +{ + ASSERT(cid); + ASSERT(resp); + ASSERT(len >= 4); + + cid->manfid = UNSTUFF_BITS(resp, 120, 8); + cid->oemid = UNSTUFF_BITS(resp, 104, 16); + cid->prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + cid->prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + cid->prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + cid->prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + cid->prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + cid->m_rev = UNSTUFF_BITS(resp, 60, 4); + cid->l_rev = UNSTUFF_BITS(resp, 56, 4); + cid->serial = (uint32_t)UNSTUFF_BITS(resp, 24, 32); + cid->year_off = UNSTUFF_BITS(resp, 8, 12); } -DRESULT sd_disk_ioctl(BYTE drv, BYTE cmd, void* buf) +void sd_dump_cid(SDcid *cid) { - ASSERT(!drv); + ASSERT(cid); + + kprintf("MANFID: %d\n", cid->manfid); + kprintf("OEMID: %d\n", cid->oemid); + kprintf("SERIAL: %ld\n", cid->serial); + kprintf("PROD_NAME: %s\n", cid->prod_name); + kprintf("REV: %d.%d\n", cid->m_rev, cid->l_rev); + kprintf("OFF,Y,M: %lx, %ld\n", cid->year_off, BCD_TO_INT_32BIT(cid->year_off)); +} - if (!sd_status) - return RES_NOTRDY; +void sd_send_init(void) +{ + if (hsmci_sendCmd(0, 0, HSMCI_CMDR_SPCMD_INIT | HSMCI_CMDR_RSPTYP_NORESP)) + kprintf("INIT Errore %lx\n", HSMCI_SR); +} + + +void sd_go_idle(void) +{ + for (int i = 0; i < 10; i++) + if (hsmci_sendCmd(0, 0, HSMCI_CMDR_RSPTYP_NORESP)) + kprintf("0 Errore %lx\n", HSMCI_SR); +} - switch (cmd) +int sd_send_if_cond(void) +{ + if (hsmci_sendCmd(8, CMD8_V_RANGE_27V_36V, HSMCI_CMDR_RSPTYP_48_BIT)) + { + kprintf("8 Errore %lx\n", HSMCI_SR); + return -1; + } + else { - case CTRL_SYNC: - return RES_OK; + uint32_t r = HSMCI_RSPR; + if ((r & 0xFFF) == CMD8_V_RANGE_27V_36V) + { + kprintf("8 ok: %lx\n", r); + return 0; + } + kprintf("8 ko: %lx\n", r); + } + return -1; +} - case GET_SECTOR_SIZE: - *(WORD *)buf = SD_DEFAULT_BLOCKLEN; - return RES_OK; +int sd_send_app_op_cond(void) +{ + for (int i = 0; i < 10; i++) + { - case GET_SECTOR_COUNT: + if (hsmci_sendCmd(55, 0, HSMCI_CMDR_RSPTYP_48_BIT)) { - CardCSD csd; - if (sd_getCSD(&csd)) - return RES_ERROR; - else + kprintf("55 Errore %lx\n", HSMCI_SR); + return -1; + } + else + { + kprintf("55 Risposta %lx\n", HSMCI_RSPR); + } + + if (hsmci_sendCmd(41, SD_HOST_VOLTAGE_RANGE | SD_OCR_CCS, HSMCI_CMDR_RSPTYP_48_BIT))// se cmd 8 va ok. + //if (hsmci_sendCmd(41, SD_HOST_VOLTAGE_RANGE, HSMCI_CMDR_RSPTYP_48_BIT)) + { + kprintf("41 Errore %lx\n", HSMCI_SR); + return -1; + } + else + { + if (HSMCI_RSPR & SD_OCR_BUSY) { - *(DWORD *)buf = csd.block_num; - return RES_OK; + kputs("sd power up!\n"); + return 0; } + kputs("sd not ready.\n"); + continue; } - case GET_BLOCK_SIZE: - *(DWORD *)buf = 1; - return RES_OK; + timer_delay(10); + } + return -1; +} - default: - LOG_ERR("unknown command: [%d]\n", cmd); - return RES_PARERR; +int sd_get_cid(uint32_t *resp, size_t len) +{ + if (hsmci_sendCmd(2, 0, HSMCI_CMDR_RSPTYP_136_BIT)) + { + kprintf("2 Errore %lx\n", HSMCI_SR); + return -1; } + else + { + hsmci_readResp(resp, len); + dump(resp, len); + } + + return 0; } -DWORD get_fattime(void) +int sd_get_csd(uint32_t *resp, size_t len) { + if (hsmci_sendCmd(9, 0, HSMCI_CMDR_RSPTYP_136_BIT)) + { + kprintf("9 Errore %lx\n", HSMCI_SR); + return -1; + } + else + { + hsmci_readResp(resp, len); + dump(resp, len); + } return 0; } + +int sd_app_status(void) +{ + if (hsmci_sendCmd(13, 0, HSMCI_CMDR_RSPTYP_48_BIT)) + { + kprintf("13 Errore %lx\n", HSMCI_SR); + return -1; + } + else + { + uint32_t status = HSMCI_RSPR; + kprintf("13 r: %lx\n", status); + if (status & SD_OCR_BUSY) + return 1; + } + return 0; +} + +#endif + + +bool sd_initUnbuf(Sd *sd, KFile *ch) +{ + if (sd_blockInit(sd, ch)) + { + sd->b.priv.vt = &sd_unbuffered_vt; + return true; + } + else + return false; +} + +static uint8_t sd_buf[SD_DEFAULT_BLOCKLEN]; + +bool sd_initBuf(Sd *sd, KFile *ch) +{ + if (sd_blockInit(sd, ch)) + { + sd->b.priv.buf = sd_buf; + sd->b.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; + sd->b.priv.vt = &sd_buffered_vt; + sd->b.priv.vt->load(&sd->b, 0); + return true; + } + else + return false; +} + + +