Files
water111 01d5fc2bbb [jak3] Decomp for gkernel, gkernel-h, gstate, gstring (#3326)
I ported the kernel test from jak1/jak2 to jak 3, and it's passing!
2024-01-21 18:08:05 -05:00

778 lines
23 KiB
C++

#include "iso_cd.h"
#include <cstdio>
#include <cstring>
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "common/util/FileUtil.h"
#include "game/common/overlord_common.h"
#include "game/overlord/common/fake_iso.h"
#include "game/overlord/common/isocommon.h"
#include "game/overlord/common/sbank.h"
#include "game/overlord/jak2/iso_queue.h"
#include "game/sce/iop.h"
#include "game/sound/sndshim.h"
using namespace iop;
namespace jak2 {
/// Page being written by CD reads
Page* ReadPagesCurrentPage = nullptr;
/// Semaphore that blocks on a CD read
s32 DvdSema = -1;
s32 BlzoSema = -1;
/// Callback function installed before using the iso_cd.cpp system
void (*PreviousCallBack)(int) = nullptr;
/// Flag to indicate that we should stop reading.
s32 ReadPagesCancelRead = 0;
/// The number of pages to read for the current read.
s32 ReadPagesNumToRead = 0;
/// The actual buffer in IOP memory to write to for the current read.
void* ReadPagesCurrentBuffer = nullptr;
/// The sector of the read in progress
s32 ReadPagesCurrentSector = 0;
/// How many sectors should be done per page (and call to sceCdRead)
s32 ReadPagesSectorsPerPage = 0;
PageList* ReadPagesPagePool = nullptr;
s32 SubBufferToRead = 0;
// -1 is set after some stuff.
// 5 or 6 needed for IsoCdPagesCallback to fire
// 5 for non-blzo read
// 6 for blzo read
// 9 is backed up by insta-reads (it happens during CD_WaitReturn)
// 8 for insta-reads itself
/// Flag that can be set to 1 once reading pages is done.
s32* ReadPagesDoneFlag = nullptr;
/// LoadStackEntry for currently reading file
static LoadStackEntry* sReadInfo;
s32 StopPluginStreams = 0;
s32 SubBuffersFlags = 0;
void* sMode = nullptr;
static LoadStackEntry sLoadStack[MAX_OPEN_FILES]; //! List of all files that are "open"
IsoFs iso_cd;
int FS_Init();
LoadStackEntry* FS_Open(FileRecord* file_record, int offset, OpenMode mode);
LoadStackEntry* FS_OpenWad(FileRecord* fr, int offset);
void FS_Close(LoadStackEntry* lse);
int FS_PageBeginRead(LoadStackEntry* lse, Buffer* buffer);
uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer);
uint32_t FS_LoadMusic(char* name, snd::BankHandle* buffer);
u32 FS_SyncRead();
struct FakeCd {
int offset_into_file = 0;
FILE* fp = nullptr;
void (*callback)(int) = nullptr;
FileRecord* last_fr = nullptr;
} gFakeCd;
void iso_cd_init_globals() {
ReadPagesCurrentPage = nullptr;
DvdSema = -1;
BlzoSema = -1;
PreviousCallBack = nullptr;
ReadPagesCancelRead = 0;
SubBufferToRead = 0;
ReadPagesNumToRead = 0;
ReadPagesCurrentBuffer = nullptr;
ReadPagesCurrentSector = 0;
ReadPagesSectorsPerPage = 0;
ReadPagesDoneFlag = nullptr;
ReadPagesPagePool = nullptr;
SpLargeBuffer = nullptr;
SubBuffersFlags = 0;
StopPluginStreams = 0;
memset(sLoadStack, 0, sizeof(sLoadStack));
sReadInfo = nullptr;
iso_cd.init = FS_Init;
iso_cd.find = FS_Find;
iso_cd.find_in = FS_FindIN;
iso_cd.get_length = FS_GetLength;
iso_cd.open = FS_Open;
iso_cd.open_wad = FS_OpenWad;
iso_cd.close = FS_Close;
iso_cd.page_begin_read = FS_PageBeginRead;
iso_cd.load_sound_bank = FS_LoadSoundBank;
iso_cd.load_music = FS_LoadMusic;
iso_cd.sync_read = FS_SyncRead;
gFakeCd.last_fr = nullptr;
}
static FILE* open_fr(FileRecord* fr, s32 thread_to_wake) {
const char* path = get_file_path(fr);
FILE* fp = file_util::open_file(path, "rb");
iop::iWakeupThread(thread_to_wake);
return fp;
}
///////////////////////////
// Sony Fake CD Functions
///////////////////////////
auto sceCdCallback(void (*callback)(int)) {
auto ret = gFakeCd.callback;
gFakeCd.callback = callback;
return ret;
}
int sceCdRead(int lsn, int num_sectors, void* dest, void* mode) {
(void)mode;
auto do_read = [lsn, num_sectors, dest](s32 thid) {
// printf("sceCdRead %d, %d -> %p\n", lsn, num_sectors, dest);
ASSERT(gFakeCd.fp);
if (fseek(gFakeCd.fp, lsn * SECTOR_SIZE, SEEK_SET)) {
ASSERT_MSG(false, "Failed to fseek");
}
if (fread(dest, num_sectors * SECTOR_SIZE, 1, gFakeCd.fp) < 0) {
printf("dest is %p, num_sectors %d, lsn %d\n", dest, num_sectors, lsn);
printf("err: %s\n", strerror(errno));
ASSERT_MSG(false, "Failed to fread");
}
ASSERT(gFakeCd.callback);
iWakeupThread(thid);
};
auto future = thpool.submit(do_read, GetThreadId());
SleepThread();
future.get();
return 1;
}
void do_cd_callback() {
if (gFakeCd.callback) {
gFakeCd.callback(1);
}
}
////////////////////////
// Overlord Functions
////////////////////////
/*!
* Handle a completed read. Called by Sony CD system.
*/
void IsoCdPagesCallback(int done) {
if (!ReadPagesCurrentPage) {
// somehow there is nothing left to read. I guess the read is no longer desired.
printf("-- ReadPagesCurrentPage was mysteriously null in IsoCdPagesCallback\n");
// allow stuff waiting on the dvd semaphore
SignalSema(DvdSema); // was iSignalSema
// restore old CD callback
sceCdCallback(PreviousCallBack);
} else if (done == 1) {
if (ReadPagesCancelRead == 0) {
// read is still in progress.
// ???
if ((SubBufferToRead != 5) && (SubBufferToRead != 6)) {
// not a FS_BeginPagedRead read, so don't use this callback. seems bad if this is reached.
return;
}
// ???
if (ReadPagesCurrentPage->state == PageState::ALLOCATED_EMPTY) {
ReadPagesCurrentPage->state = PageState::ALLOCATED_FILLED;
}
// advance to the next page.
ReadPagesCurrentPage = ReadPagesCurrentPage->next;
ReadPagesNumToRead = ReadPagesNumToRead + -1;
// kick off next read if we can.
if (ReadPagesCurrentPage && ReadPagesNumToRead > 0) {
ReadPagesCurrentBuffer = ReadPagesCurrentPage->buffer;
ReadPagesCurrentSector = ReadPagesCurrentSector + ReadPagesSectorsPerPage;
// read!
int cd_ret = sceCdRead(ReadPagesCurrentSector, ReadPagesSectorsPerPage,
ReadPagesCurrentBuffer, sMode);
if (cd_ret != 0) {
return;
}
// no need for CdReturnThread - just checks for removed CD.
// iWakeupThread(CdReturnThread);
return;
}
// otherwise, we cannot read. Hopefully we read everything the user requested
// added this check here
if (ReadPagesNumToRead) {
printf("---- IsoCdPagesCallback wants to keep reading, but ran out of pages!\n");
ASSERT_NOT_REACHED();
}
ReadPagesPagePool = 0;
ReadPagesCurrentPage = nullptr;
ReadPagesCurrentSector = 0;
if (ReadPagesDoneFlag == nullptr) {
ReadPagesDoneFlag = nullptr;
} else {
*ReadPagesDoneFlag = 1;
}
} else { // we were cancelled.
ReadPagesPagePool = 0;
ReadPagesCurrentPage = nullptr;
ReadPagesCurrentSector = 0;
ReadPagesDoneFlag = nullptr;
ReadPagesCancelRead = 0;
}
// read is done.
SubBufferToRead = -1;
sceCdCallback(PreviousCallBack);
SignalSema(DvdSema); // was iSignalSema.
}
}
// ReadDirectory : skipped
// DecodeDUP : skipped
// LoadMusicTweaks : can use common
// LoadDiscID : skipped
/*!
* Initialize the iso_cd filesystem.
*/
int FS_Init() {
// added: initialize fake_iso. This will allow us to call fake_iso functions in the implementation
// of jak 2 CD reading code.
// this will also take care of loading music tweaks
fake_iso_FS_Init();
// removed checks related to checking DVD/CD type.
SemaParam sema_param;
sema_param.attr = 0;
sema_param.init_count = 1;
sema_param.max_count = 1;
sema_param.option = 0;
DvdSema = CreateSema(&sema_param);
if (DvdSema < 0) {
printf("IOP: ======================================================================\n");
printf("IOP: iso_cd FS_Init: Can\'t create DVD semaphore\n");
printf("IOP: ======================================================================\n");
ASSERT_NOT_REACHED();
}
// removed creation of CD Return thread.
// this only checks for the CD being removed and put back in.
sema_param.attr = 1;
sema_param.init_count = 1;
sema_param.max_count = 1;
sema_param.option = 0;
BlzoSema = CreateSema(&sema_param);
if (BlzoSema < 0) {
printf("IOP: ======================================================================\n");
printf("IOP: iso_cd FS_Init: Can\'t create BLZO semaphore\n");
printf("IOP: ======================================================================\n");
ASSERT_NOT_REACHED();
}
// init the LargeBuffer.
SubBufferToRead = -1;
SubBuffersFlags = 0;
SpLargeBuffer->chunk_cnt_1 = 8;
SpLargeBuffer->chunk_cnt_2 = 8;
SpLargeBuffer->blzo_buffer_size_bytes = 0x40000;
SpLargeBuffer->current_buffer_base_ptr = nullptr;
SpLargeBuffer->page_list = SpMemoryBuffers;
SpLargeBuffer->blzo_chunk_size = 0x8000;
SpLargeBuffer->incoming_block_size = 0;
SpLargeBuffer->ptr = nullptr;
SpLargeBuffer->init0_2 = 0;
SpLargeBuffer->end_ptr = (SpLargeBuffer->current_buffer_base_ptr + 0x40000); // ?
return 0;
}
LoadStackEntry* FS_Open(FileRecord* file_record, int offset, OpenMode mode) {
// CpuSuspendIntr();
// first, find a LoadStackEntry*
LoadStackEntry* load_stack_entry = nullptr;
for (auto& entry : sLoadStack) {
if (!entry.fr) {
load_stack_entry = &entry;
load_stack_entry->fr = file_record;
break;
}
}
// CpuResumeIntr(local_28[0]);
if (!load_stack_entry) {
printf("IOP: ======================================================================\n");
printf("IOP: iso_cd FS_Open: stack full\n");
printf("IOP: ======================================================================\n");
ASSERT_NOT_REACHED();
}
u32 first_four_bytes_of_file = 0;
u32 next_four_bytes_of_file = 0;
switch (mode) {
case OpenMode::MODE0:
case OpenMode::MODE1:
// we'd read 1 sector now to check the header. this would populate first_four_bytes_of_file.
// in OpenGOAL we don't use BLZO, so just put
first_four_bytes_of_file = 0;
break;
case OpenMode::KNOWN_NOT_BLZO:
// like it was in the original
first_four_bytes_of_file = 0;
break;
default:
ASSERT_NOT_REACHED();
}
if (first_four_bytes_of_file == 0x426c5a6f) { // blzo magic.
load_stack_entry->uses_blzo = 1;
if (PollSema(BlzoSema) != 0) {
load_stack_entry->size_after_decompression = 0;
file_record->size = 0;
printf("======================================================================\n");
// printf("IOP: iso_cd FS_Open: blzo file %s cant get blzo semaphore\n", file_record);
printf("======================================================================\n");
ASSERT_NOT_REACHED();
}
// remember the size
load_stack_entry->size_after_decompression = next_four_bytes_of_file;
// also modify the file record!!
file_record->size = next_four_bytes_of_file;
// allocate a list of pages to hold the data.
Page* blzo_pages =
AllocPagesBytes(SpLargeBuffer->page_list, SpLargeBuffer->blzo_buffer_size_bytes);
SpLargeBuffer->allocated_pages = blzo_pages;
auto page_size = SpLargeBuffer->page_list->page_size;
// make sure we have enough pages.
if ((u32)blzo_pages->free_pages <
((SpLargeBuffer->blzo_buffer_size_bytes + page_size) - 1) / page_size) {
printf("IOP: ======================================================================\n");
page_size = SpLargeBuffer->page_list->page_size;
printf("IOP: iso_cd FS_Open: need %d pages got %d\n",
((SpLargeBuffer->blzo_buffer_size_bytes + page_size) - 1) / page_size,
SpLargeBuffer->allocated_pages->free_pages);
printf("IOP: ======================================================================\n");
if (0 < SpLargeBuffer->allocated_pages->free_pages) {
FreePagesList(SpLargeBuffer->page_list, SpLargeBuffer->allocated_pages);
}
StopPluginStreams = 1;
SignalSema(BlzoSema);
load_stack_entry->size_after_decompression = 0;
load_stack_entry->fr = nullptr;
return nullptr;
}
auto* page_iter = SpLargeBuffer->allocated_pages;
SpLargeBuffer->current_page = blzo_pages;
SpLargeBuffer->mid_way_page = page_iter->end_page_first_only;
SpLargeBuffer->unk_page_end2 = page_iter->end_page_first_only;
// seek page-iter to the midway page.
int midway_page_idx = page_iter->free_pages / 2;
int i = 0;
if (0 < midway_page_idx) {
do {
page_iter = page_iter->next;
i = i + 1;
} while (i < midway_page_idx);
}
SpLargeBuffer->mid_way_page = page_iter;
blzo_pages = page_iter->prev;
SpLargeBuffer->first_done_flag = 0;
SpLargeBuffer->done_flag_2 = 0;
SpLargeBuffer->unk3 = 0;
SpLargeBuffer->maybe_post_first_done = 0;
SpLargeBuffer->unk4 = 0;
SpLargeBuffer->ptr = 0;
SpLargeBuffer->page_before_midway_page = blzo_pages;
SpLargeBuffer->some_buffer = nullptr;
SpLargeBuffer->current_buffer_base_ptr = SpLargeBuffer->allocated_pages->buffer;
} else {
load_stack_entry->uses_blzo = 0;
// load_stack_entry->size_after_decompression = file_record->size;
load_stack_entry->size_after_decompression = FS_GetLength(file_record);
}
load_stack_entry->read_bytes = 0;
// load_stack_entry->cd_offset = file_record->location;
load_stack_entry->cd_offset = 0;
if (offset != -1) {
load_stack_entry->cd_offset += offset;
}
return load_stack_entry;
}
int DecompressBlock(u8* /*input*/, u8* output) {
int size_out = -1;
int decomp_return_code = -1;
// Note: in here SpLargeBuffer's ptr points to the start of the new data
// and Page's ptr points to the end.
// see if we should use decompress or not.
// in some cases, compressing the data makes it bigger.
// in this case, the data on DVD contains a CHUNK_SIZE block of uncompressed data
// and the _incoming_block_size is set to the larger-than-CHUNK_SIZE size of a compressed block.
if (SpLargeBuffer->blzo_chunk_size < SpLargeBuffer->incoming_block_size) {
// the case where compressing doesn't help. Copy data from the current page to output.
FromPagesCopy(SpLargeBuffer->current_page, SpLargeBuffer->ptr, output,
SpLargeBuffer->blzo_chunk_size);
// output size is exactly max size
size_out = SpLargeBuffer->blzo_chunk_size;
// no error possible in this case.
decomp_return_code = 0;
// adjust to the actual size of data processed.
SpLargeBuffer->incoming_block_size = size_out;
} else {
// otherwise actually decompress.
// this reads incoming_block_size data, writes decompressed to output, and stores the number
// of bytes output in size_out.
ASSERT_NOT_REACHED();
// decomp_return_code = lzo1x_decompress(input, SpLargeBuffer->incoming_block_size, output,
// &size_out, 0);
}
// align to 4 bytes so our next read is still 4 byte aligned.
auto aligned_incoming_size = SpLargeBuffer->incoming_block_size + 3U & 0xfffffffc;
SpLargeBuffer->incoming_block_size = aligned_incoming_size;
// seek the pointer in SpLargeBuffer simply by adding the size for now...
// this might run on the page...
auto* end_of_incoming = SpLargeBuffer->ptr + aligned_incoming_size;
SpLargeBuffer->ptr = end_of_incoming;
// now check to see if we need to advance the page
Page* page = SpLargeBuffer->current_page;
auto* page_ptr = page->ptr;
if (page_ptr < end_of_incoming) { // did our pointer seek go past the end of this page?
// if so, seek the page!
page = page->next;
if (page) {
SpLargeBuffer->current_page = page;
// carry over... not sure what the -1 is.
SpLargeBuffer->ptr = end_of_incoming - page_ptr + page->buffer - 1;
}
}
// check to see if there is additional data read, after this block.
if (SpLargeBuffer->ptr < SpLargeBuffer->end_ptr) {
// there is!
// we can determine the next block's size!
// read it
memcpy(&SpLargeBuffer->incoming_block_size, SpLargeBuffer->ptr, 4);
end_of_incoming = SpLargeBuffer->ptr + 4;
SpLargeBuffer->ptr = end_of_incoming;
page_ptr = SpLargeBuffer->current_page->ptr;
// check for crossing page boundary by reading this...
if (page_ptr < end_of_incoming) {
page = SpLargeBuffer->current_page->next;
if (page) {
SpLargeBuffer->current_page = page;
SpLargeBuffer->ptr = end_of_incoming - page_ptr + page->buffer - 1;
}
}
// check for insane value
if (70000 < SpLargeBuffer->incoming_block_size) {
printf("IOP: ======================================================================\n");
printf("IOP: iso_cd DecompressBlock: next compressed block length too big page %d\n",
SpLargeBuffer->current_page->maybe_page_id);
printf("IOP: ======================================================================\n");
ASSERT_NOT_REACHED();
}
} else {
// no data read. I guess we set incoming block size to 0, for now.
SpLargeBuffer->incoming_block_size = 0;
}
if (decomp_return_code != 0) {
ASSERT_NOT_REACHED();
}
return size_out;
}
int FS_PageBeginRead(LoadStackEntry* lse, Buffer* buffer) {
// bool bVar1;
// undefined4 uVar3;
// int iVar4;
// int *piVar5;
// int iVar6;
// Page *pPVar7;
// uint8_t *puVar8;
// int iVar9;
// uint uVar10;
// uint uVar11;
// PageList *plist;
// Page *pages;
// undefined4 local_40;
// undefined4 local_3c;
// undefined4 local_38;
// int local_34;
// undefined4 local_30 [2];
// _buffer = buffer->decomp_buffer;
int sector = lse->cd_offset;
// _sectors = 0;
sReadInfo = lse;
// _sector = uVar10;
// _real_sector = uVar10;
if (lse->uses_blzo == 1) {
ASSERT_NOT_REACHED_MSG("no blzo for u");
} else {
if ((lse->size_after_decompression != 0) &&
(lse->size_after_decompression <= (u32)lse->read_bytes)) {
// _sectors = 0;
// read past the end already.
// not entirely sure why this is "in progress"...
return CMD_STATUS_IN_PROGRESS;
}
// these pages will hold the data.
auto* plist = buffer->plist;
auto* pages = buffer->page;
// wait for drive
if (PollSema(DvdSema) == KE_SEMA_ZERO) {
WaitSema(DvdSema);
}
// wait for pending read to finish, I guess...
if (-1 < SubBufferToRead) {
while (-1 < SubBufferToRead) {
DelayThread(100);
}
}
// set SubBufferToRead to 5, to indicate a non-blzo FS read.
// iVar4 = CpuSuspendIntr(local_30);
SubBufferToRead = 5;
/*
if (iVar4 != -0x66) {
CpuResumeIntr(local_30[0]);
}
*/
int page_size = plist->page_size;
if (page_size < 0) { // usual page size mystery.
page_size = page_size + 0x7ff;
}
// init globals for the callback
ReadPagesCurrentBuffer = (void*)pages->buffer;
ReadPagesSectorsPerPage = page_size >> 0xb;
ReadPagesCancelRead = 0;
ReadPagesPagePool = plist;
ReadPagesCurrentPage = pages;
ReadPagesCurrentSector = sector;
int local_34 = 0; // super sketchy...
ReadPagesDoneFlag = &local_34;
int npages = pages->free_pages;
ReadPagesNumToRead = npages;
// mark all as allocated and empty.
pages->state = PageState::ALLOCATED_EMPTY;
auto* next = pages->next;
while ((next && (npages = npages + -1, 0 < npages))) {
pages = pages->next;
next = pages->next;
pages->state = PageState::ALLOCATED_EMPTY;
}
// start a read!
if (gFakeCd.last_fr != lse->fr) {
auto future = thpool.submit(open_fr, lse->fr, GetThreadId());
SleepThread();
FILE* fp = future.get();
if (!fp) {
lg::error("[OVERLORD] fake iso could not open the file \"{}\"", get_file_path(lse->fr));
} else {
// printf("PAGE READING %s\n", path);
}
ASSERT(fp);
if (gFakeCd.fp) {
fclose(gFakeCd.fp);
}
gFakeCd.fp = fp;
gFakeCd.last_fr = lse->fr;
}
while (true) {
PreviousCallBack = nullptr;
PreviousCallBack = sceCdCallback(IsoCdPagesCallback);
int ret =
sceCdRead(ReadPagesCurrentSector, ReadPagesSectorsPerPage, ReadPagesCurrentBuffer, sMode);
if (ret)
break;
sceCdCallback(PreviousCallBack);
// FS_PollDrive();
}
// wait for read to finish
while (-1 < SubBufferToRead) {
// DelayThread(1000);
do_cd_callback(); // added, to make progress. TODO remove sleep avoe.
}
// update stats.
int bytes_read = buffer->page->free_pages * buffer->plist->page_size;
lse->read_bytes = lse->read_bytes + bytes_read;
buffer->decompressed_size = bytes_read;
lse->cd_offset += bytes_read >> 0xb;
}
// not sure why we use "in progress" here, maybe the meaning changed.
return CMD_STATUS_IN_PROGRESS;
}
uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) {
SoundBank* bank = (SoundBank*)buffer;
FileRecord* file = nullptr;
char namebuf[16];
char isoname[16];
snd::BankHandle handle;
strncpy(namebuf, name, 12);
namebuf[8] = 0;
strcat(namebuf, ".sbk");
MakeISOName(isoname, namebuf);
file = FS_FindIN(isoname);
if (!file) {
return CMD_STATUS_FAILED_TO_OPEN;
}
handle = snd_BankLoadEx(get_file_path(file), 0, bank->spu_loc, bank->spu_size);
snd_ResolveBankXREFS();
bank->bank_handle = handle;
return CMD_STATUS_DONE;
}
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle) {
FileRecord* file = nullptr;
char namebuf[16];
char isoname[16];
snd::BankHandle handle;
strncpy(namebuf, name, 12);
namebuf[8] = 0;
strcat(namebuf, ".mus");
MakeISOName(isoname, namebuf);
file = FS_FindIN(isoname);
if (!file) {
return CMD_STATUS_FAILED_TO_OPEN;
}
handle = snd_BankLoadEx(get_file_path(file), 0, 0xcfcc0, 0x61a80);
snd_ResolveBankXREFS();
*bank_handle = handle;
return CMD_STATUS_DONE;
}
// CD_WaitReturn: don't need it
// FS_Find: common
// FS_FindIN: common
// FS_GetLength: common
LoadStackEntry* FS_OpenWad(FileRecord* fr, int offset) {
// CpuSuspendIntr();
LoadStackEntry* selected = nullptr;
for (uint32_t i = 0; i < MAX_OPEN_FILES; i++) {
if (!sLoadStack[i].fr) {
selected = sLoadStack + i;
selected->fr = fr;
break;
}
}
// CpuResumeIntr(local_20[0]);
if (!selected) {
printf("======================================================================\n");
printf("IOP: iso_cd FS_OpenWad: stack full\n");
printf("======================================================================\n");
ASSERT_NOT_REACHED();
}
selected->uses_blzo = 0;
selected->size_after_decompression = 0;
selected->read_bytes = 0;
// selected->cd_offset = fr->location + offset;
selected->cd_offset = offset;
return selected;
}
void FS_Close(LoadStackEntry* lse) {
if (lse->uses_blzo == 1) {
SpLargeBuffer->ptr = nullptr;
SpLargeBuffer->current_buffer_base_ptr = nullptr;
SpLargeBuffer->allocated_pages = FreePagesList(SpMemoryBuffers, SpLargeBuffer->allocated_pages);
SignalSema(BlzoSema);
if (StopPluginStreams == 1) {
StopPluginStreams = 0;
}
}
if (lse == sReadInfo) {
sReadInfo = (LoadStackEntry*)0x0;
ReadPagesCancelRead = 1;
}
lse->fr = nullptr;
}
u32 FS_SyncRead() {
if (sReadInfo) {
sReadInfo = nullptr;
return CMD_STATUS_IN_PROGRESS;
} else {
return CMD_STATUS_READ_ERR;
}
}
// FS_StoreSoundBankInIOP: stub
// FS_LoadSoundBankFromIOP: stub
// FS_LoadSoundBankFromEE: stub
// FS_PollDrive: not needed.
// CdReturn: not needed thread
// DoCdReadPages: inlined
// CheckPagesReady: inline/not used
} // namespace jak2