diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-12-28 12:18:29 +0100 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-12-28 12:18:29 +0100 |
| commit | 7e350980d5c09bbc81a0de01bf016a87ecfc4feb (patch) | |
| tree | 26b403d12eea34a4644b3d147f00e1d1455e7f52 /libpsn00b/psxcd/misc.c | |
| parent | eaec942f56ceec9c14de5c4185a02602abadd50a (diff) | |
| download | psn00bsdk-7e350980d5c09bbc81a0de01bf016a87ecfc4feb.tar.gz | |
Add CdUnlock() and DMA priority API
Diffstat (limited to 'libpsn00b/psxcd/misc.c')
| -rw-r--r-- | libpsn00b/psxcd/misc.c | 137 |
1 files changed, 99 insertions, 38 deletions
diff --git a/libpsn00b/psxcd/misc.c b/libpsn00b/psxcd/misc.c index 8fd2a4d..fc87676 100644 --- a/libpsn00b/psxcd/misc.c +++ b/libpsn00b/psxcd/misc.c @@ -12,11 +12,23 @@ #define DATA_SYNC_TIMEOUT 0x100000 -/* Private types */ - -typedef struct { - uint8_t status, first_track, last_track; -} TrackInfo; +/* Unlock command strings */ + +static char *_unlock_strings[] = { + "", + "Licensed by", + "Sony", + "Computer", + "Entertainment", + "", + "" +}; + +static const char *_unlock_regions[] = { + "of America", // CdlRegionSCEA + "(Europe)", // CdlRegionSCEE + "World wide" // CdlRegionSCEW +}; /* Sector DMA transfer functions */ @@ -77,52 +89,40 @@ int CdPosToInt(const CdlLOC *p) { ) - 150; } -/* Misc. functions */ +/* Drive unlocking API */ -int CdGetToc(CdlLOC *toc) { - TrackInfo track_info; - - if (!CdCommand(CdlGetTN, 0, 0, (uint8_t *) &track_info)) - return 0; - if (CdSync(1, 0) != CdlComplete) - return 0; - - int first = btoi(track_info.first_track); - int tracks = btoi(track_info.last_track) + 1 - first; - //assert(first == 1); - - for (int i = 0; i < tracks; i++) { - uint8_t track = itob(first + i); +CdlRegionCode CdGetRegion(void) { + uint8_t param; + uint8_t result[16]; - if (!CdCommand(CdlGetTD, &track, 1, (uint8_t *) &toc[i])) - return 0; - if (CdSync(1, 0) != CdlComplete) - return 0; + // Firmware version C0 does not support test command 0x22 to retrieve the + // region, but it was only used in the SCPH-1000 Japanese model. Version D1 + // (and possibly others?) is used in debug consoles. + // https://psx-spx.consoledev.net/cdromdrive/#19h20h-int3yymmddver + // https://psx-spx.consoledev.net/cdromdrive/#19h22h-int3for-europe + param = 0x20; + memset(result, 0, 4); - toc[i].sector = 0; - toc[i].track = track; + if (!CdCommand(CdlTest, ¶m, 1, result)) { + _sdk_log("failed to probe drive firmware version\n"); + return CdlRegionUnknown; } - return tracks; -} - -CdlRegionCode CdGetRegion(void) { - uint8_t param = 0x22; - uint8_t result[16]; + _sdk_log("drive firmware version: 0x%02x\n", result[3]); + if (result[3] == 0xc0) + return CdlRegionSCEI; + if (result[3] >= 0xd0) + return CdlRegionDebug; - // Test command 0x22 is unsupported in firmware version C0, which was used - // exclusively in the SCPH-1000 Japanese model. It's thus safe to assume - // that the console is Japanese if the command returns a valid error. - // https://psx-spx.consoledev.net/cdromdrive/#19h22h-int3for-europe + param = 0x22; memset(result, 0, 16); if (!CdCommand(CdlTest, ¶m, 1, result)) { _sdk_log("failed to probe drive region\n"); - return (result[1] == 0x10) ? CdlRegionSCEI : CdlRegionUnknown; + return CdlRegionUnknown; } _sdk_log("drive region: %s\n", result); - if (!strcmp(result, "for Japan")) return CdlRegionSCEI; if (!strcmp(result, "for U/C")) @@ -137,6 +137,67 @@ CdlRegionCode CdGetRegion(void) { return CdlRegionUnknown; } +int CdUnlock(CdlRegionCode region) { + if (region <= CdlRegionSCEI) + return 0; + if (region >= CdlRegionDebug) + return 1; + + // This is by far the most efficient way to do it. + _unlock_strings[5] = _unlock_regions[region - CdlRegionSCEA]; + + for (int i = 0; i < 7; i++) { + uint8_t result[4]; + + if (!CdCommand( + 0x50 + i, + _unlock_strings[i], + strlen(_unlock_strings[i]), + result + )) + return 0; + + if (!(result[0] & CdlStatError) || (result[1] != 0x40)) { + _sdk_log("unlock failed, status=0x%02x, code=0x%02x\n", result[0], result[1]); + return 0; + } + } + + _sdk_log("unlock successful\n"); + return CdCommand(CdlNop, 0, 0, 0); +} + +/* Misc. functions */ + +int CdGetToc(CdlLOC *toc) { + uint8_t result[4]; + + if (!CdCommand(CdlGetTN, 0, 0, result)) + return 0; + if (CdSync(1, 0) != CdlComplete) + return 0; + + int first = btoi(result[1]); + int tracks = btoi(result[2]) + 1 - first; + //assert(first == 1); + + for (int i = 0; i < tracks; i++) { + uint8_t track = itob(first + i); + + if (!CdCommand(CdlGetTD, &track, 1, result)) + return 0; + if (CdSync(1, 0) != CdlComplete) + return 0; + + toc[i].minute = result[1]; + toc[i].second = result[2]; + toc[i].sector = 0; + toc[i].track = track; + } + + return tracks; +} + int CdMix(const CdlATV *vol) { CD_REG(0) = 2; CD_REG(2) = vol->val0; |
