aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxcd/misc.c
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-12-28 12:18:29 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-12-28 12:18:29 +0100
commit7e350980d5c09bbc81a0de01bf016a87ecfc4feb (patch)
tree26b403d12eea34a4644b3d147f00e1d1455e7f52 /libpsn00b/psxcd/misc.c
parenteaec942f56ceec9c14de5c4185a02602abadd50a (diff)
downloadpsn00bsdk-7e350980d5c09bbc81a0de01bf016a87ecfc4feb.tar.gz
Add CdUnlock() and DMA priority API
Diffstat (limited to 'libpsn00b/psxcd/misc.c')
-rw-r--r--libpsn00b/psxcd/misc.c137
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, &param, 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, &param, 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;