Created
July 16, 2022 15:25
-
-
Save profi200/4c3a3f2882f0c64b421187c0b22fa2bf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
#include "mem_map.h" | |
#include "types.h" | |
#include "util.h" | |
#include "arm9/hardware/gamecard.h" | |
#include "arm9/ncch.h" | |
#include "arm9/hardware/crypto.h" | |
#include "arm9/hardware/timer.h" | |
// TODO: This belongs in cfg9.h. | |
#define CFG_REGS_BASE (IO_MEM_ARM9_ONLY) | |
#define REG_CFG9_CARDCTL *((vu16*)(CFG_REGS_BASE + 0x0000C)) | |
#define REG_CFG9_CARDSTATUS *((vu8* )(CFG_REGS_BASE + 0x00010)) | |
#define REG_CFG9_CARDCYCLES0 *((vu16*)(CFG_REGS_BASE + 0x00012)) | |
#define REG_CFG9_CARDCYCLES1 *((vu16*)(CFG_REGS_BASE + 0x00014)) | |
#define CTRCARD_REGS_BASE (IO_MEM_ARM9_ONLY + 0x4000) | |
#define REG_CTRCARDCNT *((vu32*)(CTRCARD_REGS_BASE + 0x00)) | |
#define REG_CTRCARDBLKCNT *((vu32*)(CTRCARD_REGS_BASE + 0x04)) | |
#define REG_CTRCARDSECCNT *((vu32*)(CTRCARD_REGS_BASE + 0x08)) | |
#define REG_CTRCARDSECSEED *((vu32*)(CTRCARD_REGS_BASE + 0x10)) | |
#define REGs_CTRCARDCMD ((vu32*)(CTRCARD_REGS_BASE + 0x20)) | |
#define REG_CTRCARDFIFO *((vu32*)(CTRCARD_REGS_BASE + 0x30)) | |
#define NTRCARD_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x64000) | |
#define REG_NTRCARDMCNT *((vu16*)(NTRCARD_REGS_BASE + 0x00)) | |
#define REG_NTRCARDMDATA *((vu16*)(NTRCARD_REGS_BASE + 0x02)) | |
#define REG_NTRCARDROMCNT *((vu32*)(NTRCARD_REGS_BASE + 0x04)) | |
#define REGs_NTRCARDCMD ((vu32*)(NTRCARD_REGS_BASE + 0x08)) | |
#define REG_NTRCARDSEEDX_L *((vu32*)(NTRCARD_REGS_BASE + 0x10)) | |
#define REG_NTRCARDSEEDY_L *((vu32*)(NTRCARD_REGS_BASE + 0x14)) | |
#define REG_NTRCARDSEEDX_H *((vu16*)(NTRCARD_REGS_BASE + 0x18)) | |
#define REG_NTRCARDSEEDY_H *((vu16*)(NTRCARD_REGS_BASE + 0x1A)) | |
#define REG_NTRCARDFIFO *((vu32*)(NTRCARD_REGS_BASE + 0x1C)) | |
static u32 chipId, cardType; | |
static NCCH_header ctrcardHeader; | |
static u32 cmdRand1, cmdRand2; | |
static u32 readCount; | |
static bool ctrcardSecureInit(u32 cmdBuf[4]); | |
void resetCardslot(void) | |
{ | |
REG_CFG9_CARDCYCLES0 = 0x1988; | |
REG_CFG9_CARDCYCLES1 = 0x264C; | |
// boot9 waits here. Unnecessary? | |
REG_CFG9_CARDSTATUS = 3u<<2; // Request power off | |
while(REG_CFG9_CARDSTATUS != 0); // Aotomatically changes to 0 (off) | |
TIMER_sleep(1); | |
REG_CFG9_CARDSTATUS = 1u<<2; // Prepare power on | |
TIMER_sleep(10); | |
REG_CFG9_CARDSTATUS = 2u<<2; // Power on | |
TIMER_sleep(27); | |
// Switch to NTRCARD controller. | |
REG_CFG9_CARDCTL = 0; // Select NTRCARD controller, eject IRQ off? | |
REG_NTRCARDMCNT = NTRCARD_CR1_ENABLE | NTRCARD_CR1_IRQ; | |
REG_NTRCARDROMCNT = 0x20000000; | |
TIMER_sleep(120); | |
} | |
bool gamecardInit(void) | |
{ | |
// No gamecard inserted. | |
if(REG_CFG9_CARDSTATUS & 1) return false; | |
readCount = 0; | |
resetCardslot(); | |
u32 cmdBuf[4] = {0}; | |
cmdBuf[0] = 0x9F000000; // Reset cmd | |
ntrcardCommand(cmdBuf, 0x2000, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), NULL); | |
// No idea what this is. Hardcoded in Process9. | |
static const u32 unkGarbageCmd[2] = {0x71C93FE9, 0xBB0A3B18}; | |
ntrcardCommand(unkGarbageCmd, 0, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), NULL); | |
// Send the get chip ID cmd twice like Process9. | |
cmdBuf[0] = 0x90000000; // Get chip ID cmd | |
ntrcardCommand(cmdBuf, 4, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), &chipId); | |
ntrcardCommand(cmdBuf, 4, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), NULL); | |
if(chipId & 0x10000000) | |
{ | |
cmdBuf[0] = 0xA0000000; // Get card type cmd | |
ntrcardCommand(cmdBuf, 4, 0, &cardType); | |
cmdBuf[0] = 0x3E000000; // Enter 16 byte mode cmd | |
ntrcardCommand(cmdBuf, 0, 0, NULL); | |
// Switch to CTRCARD controller. | |
REG_CTRCARDCNT = CTRCARD_nRESET; | |
REG_CFG9_CARDCTL = 2; | |
cmdBuf[0] = 0x82000000; // Read header cmd | |
ctrcardCommand(cmdBuf, 0x200, 1, 0x704802C, &ctrcardHeader); // P9: 0x9004802C 24-26 unknown | |
// Check if the header is ok. | |
if(memcmp(&ctrcardHeader.magic, "NCCH", 4) != 0) return false; | |
// The secure init function sets the cmdRand* words in cmdBuf for us. | |
if(!ctrcardSecureInit(cmdBuf)) return false; | |
u32 chipIdTest, cardTypeTest; | |
cmdBuf[0] = 0xA2000000; // Get secure chip ID cmd | |
ctrcardCommand(cmdBuf, 4, 1, 0x701002C, &chipIdTest); // P9: 0x9001002C 24-26 unknown | |
cmdBuf[0] = 0xA3000000; // Get secure card type cmd | |
ctrcardCommand(cmdBuf, 4, 1, 0x701002C, &cardTypeTest); // P9: 0x9001002C 24-26 unknown | |
if(chipIdTest == chipId && cardTypeTest == cardType) | |
{ | |
cmdBuf[0] = 0xC5000000; // Check status cmd | |
ctrcardCommand(cmdBuf, 0, 1, 0x100002C, NULL); // P9: 0x9000002C, 24-26 unknown | |
} | |
cmdBuf[0] = 0xA2000000; // Get secure chip ID cmd | |
for(u32 i = 0; i < 5; i++) | |
{ | |
ctrcardCommand(cmdBuf, 4, 1, 0x701002C, NULL); // P9: 0x9001002C 24-26 unknown | |
} | |
} | |
return true; | |
} | |
u32 getChipId(void) | |
{ | |
return chipId; | |
} | |
u32 getCardType(void) | |
{ | |
return cardType; | |
} | |
////////////////////////////////// | |
// NTRCARD // | |
////////////////////////////////// | |
void ntrcardCommand(const u32 command[2], u32 pageSize, u32 latency, void* buffer) | |
{ | |
REG_NTRCARDMCNT = NTRCARD_CR1_ENABLE; | |
REGs_NTRCARDCMD[0] = swap32(command[0]); | |
REGs_NTRCARDCMD[1] = swap32(command[1]); | |
pageSize -= pageSize & 3; // align to 4 byte | |
u32 pageParam = NTRCARD_PAGESIZE_4K; | |
u32 transferLength = 4096; | |
// make zero read and 4 byte read a little special for timing optimization(and 512 too) | |
switch (pageSize) { | |
case 0: | |
transferLength = 0; | |
pageParam = NTRCARD_PAGESIZE_0; | |
break; | |
case 4: | |
transferLength = 4; | |
pageParam = NTRCARD_PAGESIZE_4; | |
break; | |
case 512: | |
transferLength = 512; | |
pageParam = NTRCARD_PAGESIZE_512; | |
break; | |
case 8192: | |
transferLength = 8192; | |
pageParam = NTRCARD_PAGESIZE_8K; | |
break; | |
default: | |
break; //Using 4K pagesize and transfer length by default | |
} | |
// go | |
REG_NTRCARDROMCNT = 0x10000000; | |
REG_NTRCARDROMCNT = NTRKEY_PARAM | NTRCARD_ACTIVATE | NTRCARD_nRESET | pageParam | latency; | |
u8 * pbuf = (u8 *)buffer; | |
u32 * pbuf32 = (u32 * )buffer; | |
bool useBuf = ( NULL != pbuf ); | |
bool useBuf32 = (useBuf && (0 == (3 & ((u32)buffer)))); | |
u32 count = 0; | |
u32 cardCtrl = REG_NTRCARDROMCNT; | |
if(useBuf32) | |
{ | |
while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) | |
{ | |
cardCtrl = REG_NTRCARDROMCNT; | |
if( cardCtrl & NTRCARD_DATA_READY ) { | |
u32 data = REG_NTRCARDFIFO; | |
*pbuf32++ = data; | |
count += 4; | |
} | |
} | |
} | |
else if(useBuf) | |
{ | |
while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) | |
{ | |
cardCtrl = REG_NTRCARDROMCNT; | |
if( cardCtrl & NTRCARD_DATA_READY ) { | |
u32 data = REG_NTRCARDFIFO; | |
pbuf[0] = (unsigned char) (data >> 0); | |
pbuf[1] = (unsigned char) (data >> 8); | |
pbuf[2] = (unsigned char) (data >> 16); | |
pbuf[3] = (unsigned char) (data >> 24); | |
pbuf += sizeof (unsigned int); | |
count += 4; | |
} | |
} | |
} | |
else | |
{ | |
while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) | |
{ | |
cardCtrl = REG_NTRCARDROMCNT; | |
if( cardCtrl & NTRCARD_DATA_READY ) { | |
u32 data = REG_NTRCARDFIFO; | |
(void)data; | |
count += 4; | |
} | |
} | |
} | |
// if read is not finished, ds will not pull ROM CS to high, we pull it high manually | |
if( count != transferLength ) { | |
// MUST wait for next data ready, | |
// if ds pull ROM CS to high during 4 byte data transfer, something will mess up | |
// so we have to wait next data ready | |
do { cardCtrl = REG_NTRCARDROMCNT; } while(!(cardCtrl & NTRCARD_DATA_READY)); | |
// and this tiny delay is necessary | |
//ioAK2Delay(33); | |
// pull ROM CS high | |
REG_NTRCARDROMCNT = 0x10000000; | |
REG_NTRCARDROMCNT = NTRKEY_PARAM | NTRCARD_ACTIVATE | NTRCARD_nRESET; // | 0 | 0x0000; | |
} | |
// wait rom cs high | |
do { cardCtrl = REG_NTRCARDROMCNT; } while( cardCtrl & NTRCARD_BUSY ); | |
//lastCmd[0] = command[0];lastCmd[1] = command[1]; | |
} | |
////////////////////////////////// | |
// CTRCARD // | |
////////////////////////////////// | |
void ctrcardCommand(const u32 command[4], u32 pageSize, u32 blocks, u32 latency, void* buffer) | |
{ | |
REGs_CTRCARDCMD[0] = command[3]; | |
REGs_CTRCARDCMD[1] = command[2]; | |
REGs_CTRCARDCMD[2] = command[1]; | |
REGs_CTRCARDCMD[3] = command[0]; | |
//Make sure this never happens | |
if(blocks == 0) blocks = 1; | |
pageSize -= pageSize & 3; // align to 4 byte | |
u32 pageParam = CTRCARD_PAGESIZE_4K; | |
u32 transferLength = 4096; | |
// make zero read and 4 byte read a little special for timing optimization(and 512 too) | |
switch(pageSize) { | |
case 0: | |
transferLength = 0; | |
pageParam = CTRCARD_PAGESIZE_0; | |
break; | |
case 4: | |
transferLength = 4; | |
pageParam = CTRCARD_PAGESIZE_4; | |
break; | |
case 64: | |
transferLength = 64; | |
pageParam = CTRCARD_PAGESIZE_64; | |
break; | |
case 512: | |
transferLength = 512; | |
pageParam = CTRCARD_PAGESIZE_512; | |
break; | |
case 1024: | |
transferLength = 1024; | |
pageParam = CTRCARD_PAGESIZE_1K; | |
break; | |
case 2048: | |
transferLength = 2048; | |
pageParam = CTRCARD_PAGESIZE_2K; | |
break; | |
case 4096: | |
transferLength = 4096; | |
pageParam = CTRCARD_PAGESIZE_4K; | |
break; | |
default: | |
break; //Defaults already set | |
} | |
REG_CTRCARDBLKCNT = blocks - 1; | |
transferLength *= blocks; | |
// go | |
REG_CTRCARDCNT = 0x10000000; | |
REG_CTRCARDCNT = CTRCARD_ACTIVATE | CTRCARD_nRESET | pageParam | latency; | |
u8 * pbuf = (u8 *)buffer; | |
u32 * pbuf32 = (u32 * )buffer; | |
bool useBuf = ( NULL != pbuf ); | |
bool useBuf32 = (useBuf && (0 == (3 & ((u32)buffer)))); | |
u32 count = 0; | |
u32 cardCtrl = REG_CTRCARDCNT; | |
if(useBuf32) | |
{ | |
while( (cardCtrl & CTRCARD_BUSY) && count < transferLength) | |
{ | |
cardCtrl = REG_CTRCARDCNT; | |
if( cardCtrl & CTRCARD_DATA_READY ) { | |
u32 data = REG_CTRCARDFIFO; | |
*pbuf32++ = data; | |
count += 4; | |
} | |
} | |
} | |
else if(useBuf) | |
{ | |
while( (cardCtrl & CTRCARD_BUSY) && count < transferLength) | |
{ | |
cardCtrl = REG_CTRCARDCNT; | |
if( cardCtrl & CTRCARD_DATA_READY ) { | |
u32 data = REG_CTRCARDFIFO; | |
pbuf[0] = (unsigned char) (data >> 0); | |
pbuf[1] = (unsigned char) (data >> 8); | |
pbuf[2] = (unsigned char) (data >> 16); | |
pbuf[3] = (unsigned char) (data >> 24); | |
pbuf += sizeof (unsigned int); | |
count += 4; | |
} | |
} | |
} | |
else | |
{ | |
while( (cardCtrl & CTRCARD_BUSY) && count < transferLength) | |
{ | |
cardCtrl = REG_CTRCARDCNT; | |
if( cardCtrl & CTRCARD_DATA_READY ) { | |
u32 data = REG_CTRCARDFIFO; | |
(void)data; | |
count += 4; | |
} | |
} | |
} | |
// if read is not finished, ds will not pull ROM CS to high, we pull it high manually | |
if( count != transferLength ) { | |
// MUST wait for next data ready, | |
// if ds pull ROM CS to high during 4 byte data transfer, something will mess up | |
// so we have to wait next data ready | |
do { cardCtrl = REG_CTRCARDCNT; } while(!(cardCtrl & CTRCARD_DATA_READY)); | |
// and this tiny delay is necessary | |
wait(66); | |
// pull ROM CS high | |
REG_CTRCARDCNT = 0x10000000; | |
REG_CTRCARDCNT = CTRKEY_PARAM | CTRCARD_ACTIVATE | CTRCARD_nRESET; | |
} | |
// wait rom cs high | |
do { cardCtrl = REG_CTRCARDCNT; } while( cardCtrl & CTRCARD_BUSY ); | |
//lastCmd[0] = command[0];lastCmd[1] = command[1]; | |
} | |
void ctrcardReadData(u32 sector, u32 length, u32 blocks, void* buffer) | |
{ | |
u32 cmdBuf[4] = {0}; | |
if(readCount++ >= 10000) | |
{ | |
readCount = 0; | |
cmdBuf[0] = 0xC5000000; // Check status cmd | |
cmdBuf[2] = cmdRand1; | |
cmdBuf[3] = cmdRand2; | |
ctrcardCommand(cmdBuf, 0, 1, 0x100002C, NULL); // P9: 0x9000002C, 24-26 unknown | |
cmdBuf[2] = 0; | |
cmdBuf[3] = 0; | |
} | |
// This may not be needed if gamecards >4 GiB don't exist. P9 does it anyway. | |
cmdBuf[0] = 0xBF000000 | sector>>23; // Read ROM cmd | |
cmdBuf[1] = sector<<9; | |
ctrcardCommand(cmdBuf, length, blocks, 0x704822C, buffer); // P9: 0xD104822C, 24-26 hardcoded | |
} | |
NCCH_header* ctrcardGetHeader(void) | |
{ | |
return &ctrcardHeader; | |
} | |
void ctrcardGetUniqueId(u32 *buf) | |
{ | |
// TODO: Do we need cmdRand* here? Doesn't look like it's needed. | |
const u32 uniqueIdCmd[4] = {0xC6000000, 0x00000000, 0x00000000, 0x00000000}; | |
ctrcardCommand(uniqueIdCmd, 0x40, 1, 0x701002C, buf); // P9: 0x9003002C, 24-26 unknown | |
} | |
static void ctrcardSetSecSeed(const u32 seed[4], bool flag) | |
{ | |
// Select secure crypto key? | |
if(flag) REG_CTRCARDSECCNT = ((cardType & 3u) << 8) | 4; | |
REG_CTRCARDSECSEED = seed[0]; | |
REG_CTRCARDSECSEED = seed[1]; | |
REG_CTRCARDSECSEED = seed[2]; | |
REG_CTRCARDSECSEED = seed[3]; | |
REG_CTRCARDSECCNT |= 0x8000; | |
while(!(REG_CTRCARDSECCNT & 0x4000)); | |
if(flag) (*(vu32*)0x1000400C) = 0x00000001; // Enable card command encryption? | |
} | |
static bool ctrcardSecureInit(u32 cmdBuf[4]) | |
{ | |
if((cardType & 3u) == 3) // Dev card | |
{ | |
static const u32 devCardKey[4] = {0}; | |
AES_setKey(0x11, AES_KEY_NORMAL, AES_INPUT_BIG | AES_INPUT_NORMAL, false, devCardKey); | |
AES_selectKeyslot(0x11); | |
} | |
else // Retail card | |
{ | |
AES_setKey(0x3B, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, ctrcardHeader.seedKeyY); | |
AES_selectKeyslot(0x3B); | |
} | |
u32 seed[4]; | |
AES_ctx ctx; | |
AES_setNonce(&ctx, AES_INPUT_BIG | AES_INPUT_NORMAL, ctrcardHeader.seedNonce); | |
AES_setCryptParams(&ctx, AES_INPUT_BIG | AES_INPUT_NORMAL, AES_OUTPUT_LITTLE | AES_OUTPUT_REVERSED); | |
if(!AES_ccm(&ctx, ctrcardHeader.encryptedSeed, seed, 16, ctrcardHeader.seedAesMac, 1, false)) return false; | |
ctrcardSetSecSeed(seed, true); | |
cmdRand1 = REG_PRNG[0]; | |
cmdRand2 = REG_PRNG[4]; | |
cmdBuf[0] = 0x83000000; // Seed cmd | |
cmdBuf[2] = cmdRand1; | |
cmdBuf[3] = cmdRand2; | |
ctrcardCommand(cmdBuf, 0, 1, 0x700822C, NULL); // P9: 0x9000002C, 24-26 unknown | |
seed[0] = cmdRand2; | |
seed[1] = cmdRand1; | |
ctrcardSetSecSeed(seed, false); | |
return true; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "types.h" | |
#include "arm9/ncch.h" | |
#define CARD_ENABLE (1u<<15) | |
#define CARD_SPI_ENABLE (1u<<13) | |
#define CARD_SPI_BUSY (1u<<7) | |
#define CARD_SPI_HOLD (1u<<6) | |
void resetCardslot(void); | |
bool gamecardInit(void); | |
u32 getChipId(void); | |
u32 getCardType(void); | |
////////////////////////////////// | |
// NTRCARD // | |
////////////////////////////////// | |
#define NTRCARD_PAGESIZE_0 (0u<<24) | |
#define NTRCARD_PAGESIZE_4 (7u<<24) | |
#define NTRCARD_PAGESIZE_512 (1u<<24) | |
#define NTRCARD_PAGESIZE_1K (2u<<24) | |
#define NTRCARD_PAGESIZE_2K (3u<<24) | |
#define NTRCARD_PAGESIZE_4K (4u<<24) | |
#define NTRCARD_PAGESIZE_8K (5u<<24) | |
#define NTRCARD_PAGESIZE_16K (6u<<24) | |
#define NTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling | |
#define NTRCARD_WR (1u<<30) // Card write enable | |
#define NTRCARD_nRESET (1u<<29) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) | |
#define NTRCARD_SEC_LARGE (1u<<28) // Use "other" secure area mode, which tranfers blocks of 0x1000 bytes at a time | |
#define NTRCARD_CLK_SLOW (1u<<27) // Transfer clock rate (0 = 6.7MHz, 1 = 4.2MHz) | |
#define NTRCARD_BLK_SIZE(n) ((n & 0x7u)<<24) // Transfer block size, (0 = None, 1..6 = (0x100 << n) bytes, 7 = 4 bytes) | |
#define NTRCARD_SEC_CMD (1u<<22) // The command transfer will be hardware encrypted (KEY2) | |
#define NTRCARD_DELAY2(n) ((n & 0x3Fu)<<16) // Transfer delay length part 2 | |
#define NTRCARD_SEC_SEED (1u<<15) // Apply encryption (KEY2) seed to hardware registers | |
#define NTRCARD_SEC_EN (1u<<14) // Security enable | |
#define NTRCARD_SEC_DAT (1u<<13) // The data transfer will be hardware encrypted (KEY2) | |
#define NTRCARD_DELAY1(n) (n & 0x1FFFu) // Transfer delay length part 1 | |
// 3 bits in b10..b8 indicate something | |
// read bits | |
#define NTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? | |
#define NTRCARD_DATA_READY (1u<<23) // when reading, REG_NTRCARDFIFO has another word of data and is good to go | |
// Card commands | |
#define NTRCARD_CMD_DUMMY (0x9Fu) | |
#define NTRCARD_CMD_HEADER_READ (0x00u) | |
#define NTRCARD_CMD_HEADER_CHIPID (0x90u) | |
#define NTRCARD_CMD_ACTIVATE_BF (0x3Cu) // Go into blowfish (KEY1) encryption mode | |
#define NTRCARD_CMD_ACTIVATE_SEC (0x40u) // Go into hardware (KEY2) encryption mode | |
#define NTRCARD_CMD_SECURE_CHIPID (0x10u) | |
#define NTRCARD_CMD_SECURE_READ (0x20u) | |
#define NTRCARD_CMD_DISABLE_SEC (0x60u) // Leave hardware (KEY2) encryption mode | |
#define NTRCARD_CMD_DATA_MODE (0xA0u) | |
#define NTRCARD_CMD_DATA_READ (0xB7u) | |
#define NTRCARD_CMD_DATA_CHIPID (0xB8u) | |
#define NTRCARD_CR1_ENABLE (0x8000u) | |
#define NTRCARD_CR1_IRQ (0x4000u) | |
#define NTRKEY_PARAM (0x3F1FFFu) | |
void ntrcardCommand(const u32 command[2], u32 pageSize, u32 latency, void* buffer); | |
////////////////////////////////// | |
// CTRCARD // | |
////////////////////////////////// | |
#define CTRCARD_PAGESIZE_0 (0u<<16) | |
#define CTRCARD_PAGESIZE_4 (1u<<16) | |
#define CTRCARD_PAGESIZE_16 (2u<<16) | |
#define CTRCARD_PAGESIZE_64 (3u<<16) | |
#define CTRCARD_PAGESIZE_512 (4u<<16) | |
#define CTRCARD_PAGESIZE_1K (5u<<16) | |
#define CTRCARD_PAGESIZE_2K (6u<<16) | |
#define CTRCARD_PAGESIZE_4K (7u<<16) | |
#define CTRCARD_PAGESIZE_16K (8u<<16) | |
#define CTRCARD_PAGESIZE_64K (9u<<16) | |
#define CTRCARD_CRC_ERROR (1u<<4) | |
#define CTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling | |
#define CTRCARD_IE (1u<<30) // Interrupt enable | |
#define CTRCARD_WR (1u<<29) // Card write enable | |
#define CTRCARD_nRESET (1u<<28) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) | |
#define CTRCARD_BLK_SIZE(n) ((n & 0xFu)<<16) // Transfer block size | |
#define CTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? | |
#define CTRCARD_DATA_READY (1u<<27) // when reading, REG_CTRCARDFIFO has another word of data and is good to go | |
#define CTRKEY_PARAM (0x1000000u) | |
void ctrcardCommand(const u32 command[4], u32 pageSize, u32 blocks, u32 latency, void* buffer); | |
void ctrcardReadData(u32 sector, u32 length, u32 blocks, void* buffer); | |
NCCH_header* ctrcardGetHeader(void); | |
void ctrcardGetUniqueId(u32 *buf); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment