void TWLCard::restoreSaveFile(u8* in, void (*cb)(u32, u32)) const { u32 sz = saveSize(); u32 pageSize = SPIGetPageSize(cardType_); cb(0, sz); for(u32 i = 0; i < sz/pageSize; ++i){ Result res = SPIWriteSaveData(cardType_, pageSize*i, in + pageSize*i, pageSize); if(res != 0) throw Error(res, __FILE__, __LINE__); cb(pageSize*(i+1), sz); } }
Result SPIWriteSaveData(CardType type, u32 offset, void* data, u32 size) { u8 cmd[4] = { 0 }; u32 cmdSize = 4; u32 end = offset + size; u32 pos = offset; if(size == 0) return 0; u32 pageSize = SPIGetPageSize(type); if(pageSize == 0) return 0xC8E13404; Result res = SPIWaitWriteEnd(type); if(res) return res; size = (size <= SPIGetCapacity(type) - offset) ? size : SPIGetCapacity(type) - offset; while(pos < end) { switch(type) { case EEPROM_512B: cmdSize = 2; cmd[0] = (pos >= 0x100) ? SPI_512B_EEPROM_CMD_WRHI : SPI_512B_EEPROM_CMD_WRLO; cmd[1] = (u8) pos; break; case EEPROM_8KB: case EEPROM_64KB: cmdSize = 3; cmd[0] = SPI_CMD_PP; cmd[1] = (u8)(pos >> 8); cmd[2] = (u8) pos; break; case FLASH_256KB_1: /* This is what is done in the official implementation, but I think it's wrong cmdSize = 4; cmd[0] = SPI_CMD_PP; cmd[1] = (u8)(pos >> 16); cmd[2] = (u8)(pos >> 8); cmd[3] = (u8) pos; break; */ case FLASH_256KB_2: case FLASH_512KB_1: case FLASH_512KB_2: case FLASH_1MB: case FLASH_512KB_INFRARED: case FLASH_256KB_INFRARED: cmdSize = 4; cmd[0] = SPI_FLASH_CMD_PW; cmd[1] = (u8)(pos >> 16); cmd[2] = (u8)(pos >> 8); cmd[3] = (u8) pos; break; case FLASH_8MB: return 0xC8E13404; // writing is unsupported (so is reading? need to test) default: return 0; // never happens } u32 remaining = end - pos; u32 nb = pageSize - (pos % pageSize); u32 dataSize = (remaining < nb) ? remaining : nb; if( (res = SPIEnableWriting(type)) ) return res; if( (res = SPIWriteRead(type, cmd, cmdSize, NULL, 0, (void*) ((u8*) data - offset + pos), dataSize)) ) return res; if( (res = SPIWaitWriteEnd(type)) ) return res; pos = ((pos / pageSize) + 1) * pageSize; // truncate } return 0; }