1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-01-11 23:43:04 +00:00
2024-05-05 01:52:01 +02:00

196 lines
4.7 KiB
C

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "psx.h"
#include "cue_parser.h"
#include "user_io.h"
#include "data_io.h"
#include "utils.h"
#include "debug.h"
typedef enum
{
UNKNOWN = 0,
JP,
US,
EU
} region_t;
static char *region_str[] = {"Unknown", "JP", "US", "EU"};
typedef struct
{
uint32_t track_count;
uint32_t total_lba;
uint32_t total_bcd;
uint16_t libcrypt_mask;
uint16_t metadata; // lower 2 bits encode the region, 3rd bit is reset request, the other bits are reseved
} __attribute__ ((packed)) disk_header_t;
typedef struct
{
uint32_t start_lba;
uint32_t end_lba;
uint32_t bcd;
uint32_t reserved;
} __attribute__ ((packed)) track_t;
#define SBI_HEADER_SIZE 4
#define SBI_BLOCK_SIZE 14
static uint32_t libCryptSectors[16] =
{
14105,
14231,
14485,
14579,
14649,
14899,
15056,
15130,
15242,
15312,
15378,
15628,
15919,
16031,
16101,
16167,
};
static uint16_t psx_libCryptMask(FIL* sbi_file)
{
UINT br;
uint16_t mask = 0;
if ((f_read(sbi_file, sector_buffer, SECTOR_BUFFER_SIZE, &br)) == FR_OK)
{
for (int i = 0;; i++)
{
int pos = SBI_HEADER_SIZE + i * SBI_BLOCK_SIZE;
if (pos >= br) break;
uint32_t lba = 150 + MSF2LBA(bcd2bin(sector_buffer[pos]), bcd2bin(sector_buffer[pos + 1]), bcd2bin(sector_buffer[pos + 2]));
psx_debugf("Testing lba from SBI: %d", lba);
for (int m = 0; m < 16; m++) if (libCryptSectors[m] == lba) mask |= (1 << (15 - m));
}
}
return mask;
}
static void psx_read_sector(char* buffer, unsigned int lba)
{
UINT br;
if (!toc.valid) {
memset(buffer, 0, 2352);
return;
}
int index = cue_gettrackbylba(lba);
int offset = (lba - toc.tracks[index].start) * toc.tracks[index].sector_size + toc.tracks[index].offset;
//psx_debugf("read CD lba=%d, track=%d offset=%d (trackstart=%d tracoffset=%d tracksectorsize=%d)", lba, index, offset, toc.tracks[index].start, toc.tracks[index].offset, toc.tracks[index].sector_size);
if (toc.tracks[index].sector_size != 2352) {
// unsupported sector size by the core
memset(buffer, 0, 2352);
} else {
DISKLED_ON
f_lseek(&toc.file->file, offset);
f_read(&toc.file->file, buffer, 2352, &br);
DISKLED_OFF
}
return;
}
static void psx_send_cue_and_metadata(uint16_t libcrypt_mask, region_t region, int reset)
{
disk_header_t header;
track_t track;
msf_t msf;
header.track_count = (bin2bcd(toc.last) << 8) | toc.last;
header.total_lba = toc.end;
LBA2MSF(toc.end, &msf);
header.total_bcd = (bin2bcd(msf.m) << 8) | bin2bcd(msf.s);
header.libcrypt_mask = libcrypt_mask;
header.metadata = region; // the lower 2 bits of metadata contain the region
if (reset) header.metadata |= 4; // 3rd bit is reset request
data_io_set_index(251);
data_io_file_tx_start();
EnableFpga();
SPI(DIO_FILE_TX_DAT);
spi_write((const char *)&header, sizeof(disk_header_t));
track.reserved = 0;
for (int i = 0; i < toc.last; i++) {
track.start_lba = toc.tracks[i].start;
track.end_lba = toc.tracks[i].end;
LBA2MSF(toc.tracks[i].start + 150, &msf);
track.bcd = ((bin2bcd(msf.m) << 8) | bin2bcd(msf.s)) | ((toc.tracks[i].type ? 0 : 1) << 16);
psx_debugf("%d start_lba=%d end_lba=%d bcd=%04x", i, track.start_lba, track.end_lba, track.bcd);
spi_write((const char *)&track, sizeof(track_t));
}
DisableFpga();
data_io_file_tx_done();
}
static region_t psx_get_region()
{
int license_sector = 4;
psx_read_sector(sector_buffer, license_sector);
uint8_t* license_start = (uint8_t*)memmem(sector_buffer, 2352, " Licensed by Sony Computer Entertainment ", 60);
if (license_start) {
const uint8_t* region_start = license_start + 60;
if (memcmp(region_start, "Amer ica ", 10) == 0)
return US;
if (memcmp(region_start, "Inc.", 4) == 0)
return JP;
if (memcmp(region_start, "Euro pe", 7) == 0)
return EU;
}
return UNKNOWN;
}
void psx_mount_cd(const unsigned char *name)
{
if (!toc.valid) return;
region_t region = psx_get_region();
uint16_t libcrypt_mask = 0;
const char *fileExt = 0;
int len = strlen(name);
while(len > 2) {
if (name[len-2] == '.') {
fileExt = &name[len-1];
break;
}
len--;
}
if (fileExt) {
char sbi[len+3];
memcpy(sbi, name, len-1);
strcpy(&sbi[len-1], "SBI");
FIL sbi_f;
iprintf("PSX: trying SBI file (%s)\n", sbi);
if(f_open(&sbi_f, sbi, FA_READ) == FR_OK) {
libcrypt_mask = psx_libCryptMask(&sbi_f);
f_close(&sbi_f);
}
}
iprintf("PSX: CD region: %s crypt_mask: %04x\n", region_str[region], libcrypt_mask);
psx_send_cue_and_metadata(libcrypt_mask, region, 0);
}
void psx_read_cd(uint8_t drive_index, unsigned int lba)
{
user_io_sd_ack(drive_index);
if (lba>=150) lba-=150;
psx_read_sector(sector_buffer, lba);
spi_uio_cmd_cont(UIO_SECTOR_RD);
spi_write(sector_buffer, 2352);
DisableIO();
}