thug/Code/Sys/File/ngps/p_AsyncFilesys.cpp
2016-02-14 08:39:12 +11:00

1291 lines
44 KiB
C++

///////////////////////////////////////////////////////////////////////////////////////
//
// p_AsyncFilesys.cpp GRJ 11 Oct 2002
//
// Asynchronous file system
//
///////////////////////////////////////////////////////////////////////////////////////
#include <sys/config/config.h>
#include <sys/file/ngps/p_AsyncFilesys.h>
#include <sys/file/ngps/hed.h>
#include <sys/file/ngps/FileIO/FileIO.h>
#include <eetypes.h>
#include <eekernel.h>
#include <sif.h>
#include <sifrpc.h>
namespace File
{
// Debug info
#define SHOW_ASYNC_INFO 0
#if SHOW_ASYNC_INFO
#define ShowAsyncInfo(A...) scePrintf(##A)
#else
#define ShowAsyncInfo(A...)
#endif
extern SHed *gpHed; // Made global for p_AsyncFilesystem
extern unsigned int gWadLSN;
///////////////////////////////////////////////////////////////////////////////////////
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2AsyncFileHandle::CPs2AsyncFileHandle()
{
m_file_handle_index = -1;
m_num_open_requests = 0;
mp_non_aligned_buffer = NULL;
mp_temp_aligned_buffer = NULL;
mp_temp_aligned_buffer_base = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPs2AsyncFileHandle::~CPs2AsyncFileHandle()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::io_callback(EAsyncFunctionType function, int result, uint32 data)
{
SFileIOResultPacket *p_packet = (SFileIOResultPacket *) data;
int return_data = p_packet->m_return_data;
// Do any special function processing
switch (function)
{
case FUNC_OPEN:
m_file_handle_index = result; // Save IOP file handle index
if (result < 0)
{
//Dbg_MsgAssert(0, ("Error: Async open returned %d", result));
m_file_size = 0;
} else {
m_file_size = return_data;
ShowAsyncInfo("io_callback: Open returned handle index %d with filesize %d\n", result, return_data);
}
break;
case FUNC_SEEK:
if (result < 0)
{
Dbg_MsgAssert(0, ("Error: Async seek returned %d", result));
} else {
m_position = result;
}
break;
case FUNC_LOAD:
case FUNC_READ:
if (mp_temp_aligned_buffer && (result > 0))
{
ShowAsyncInfo("Copying from %x to %x of size %d", mp_temp_aligned_buffer, mp_non_aligned_buffer, result);
memcpy(mp_non_aligned_buffer, mp_temp_aligned_buffer, result);
}
// don't break, continue on below
case FUNC_WRITE:
if (result < 0)
{
Dbg_MsgAssert(0, ("Error: Async IO returned %d", result));
} else {
m_position += result;
if (mp_temp_aligned_buffer)
{
CPs2AsyncFileLoader::sIAddBufferToFreeList(mp_temp_aligned_buffer_base);
mp_non_aligned_buffer = NULL;
mp_temp_aligned_buffer = NULL;
mp_temp_aligned_buffer_base = NULL;
}
}
break;
case FUNC_CLOSE:
if (get_busy_count() > 1)
{
scePrintf("********* ERROR: Still other %d requests open after close completed on handle %x and request id %d\n", get_busy_count() - 1, this, p_packet->m_header.opt);
//while (1)
// ;
}
break;
case FUNC_IDLE:
// Don't want m_busy to change or user-defined callback to be executed
return;
default:
break;
}
// Check to make sure request buffer will be clear
if (get_busy_count() > 0)
{
//Dbg_MsgAssert(m_num_open_requests == 1, ("Sill other open requests"));
}
// Now handle the above p-line stuff
CAsyncFileHandle::io_callback(function, result, return_data);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::non_cache_aligned_data_copy(SFileIOResultPacket *p_result, bool last_packet)
{
Dbg_Assert(p_result->m_non_aligned_data_size > 0);
int request_id = p_result->m_header.opt;
const SRequest *p_request = get_request(request_id);
Dbg_Assert(p_request);
Dbg_Assert(p_request->mp_buffer);
// Check if it goes at the start or end
if (last_packet)
{
// end of buffer
memcpy((void *) ((uint32) p_request->mp_buffer + (p_request->m_buffer_size - p_result->m_non_aligned_data_size)),
p_result->m_non_aligned_data, p_result->m_non_aligned_data_size);
}
else
{
// beginning of buffer
memcpy(p_request->mp_buffer, p_result->m_non_aligned_data, p_result->m_non_aligned_data_size);
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2AsyncFileHandle::add_request_id(int request_id, EAsyncFunctionType function, SFileIORequestPacket *p_packet)
{
if (m_num_open_requests >= NUM_REQUESTS)
{
Dbg_MsgAssert(0, ("Too many open requests for file handle"));
return false;
}
// We must disable interrupts here so that the IO interrupts don't change things underneath us.
DI();
// Save buffer info if it is a read
if (p_packet->m_request.m_command == FILEIO_READ)
{
m_open_requests[m_num_open_requests].mp_buffer = (uint8 *) p_packet->m_request.m_param.m_rw.m_buffer;
m_open_requests[m_num_open_requests].m_buffer_size = p_packet->m_request.m_param.m_rw.m_size;
}
else
{
m_open_requests[m_num_open_requests].mp_buffer = NULL;
m_open_requests[m_num_open_requests].m_buffer_size = 0;
}
m_open_requests[m_num_open_requests].m_request_id = request_id;
m_open_requests[m_num_open_requests++].m_function = function;
// And re-enable interrupts
EI();
//scePrintf("Adding request %d to entry #%d for %x with busy %d\n", request_id, (m_num_open_requests-1), this, get_busy_count());
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
EAsyncFunctionType CPs2AsyncFileHandle::get_request_function(int request_id) const
{
// Find request id in list
for (int i = 0; i < m_num_open_requests; i++)
{
if (m_open_requests[i].m_request_id == request_id)
{
return m_open_requests[i].m_function;
}
}
// Request not found
Dbg_MsgAssert(0, ("Can't find request %d on %x", request_id, this));
return FUNC_IDLE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
const CPs2AsyncFileHandle::SRequest * CPs2AsyncFileHandle::get_request(int request_id) const
{
// Find request id in list
for (int i = 0; i < m_num_open_requests; i++)
{
if (m_open_requests[i].m_request_id == request_id)
{
return &(m_open_requests[i]);
}
}
// Request not found
Dbg_MsgAssert(0, ("Can't find request %d on %x", request_id, this));
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2AsyncFileHandle::clear_request_id(int request_id)
{
if (m_num_open_requests <= 0)
{
Dbg_MsgAssert(0, ("Can't clear request: Open request list empty"));
return false;
}
// Find request id in list
for (int i = 0; i < m_num_open_requests; i++)
{
if (m_open_requests[i].m_request_id == request_id)
{
// Just move end of list to here
m_open_requests[i] = m_open_requests[--m_num_open_requests];
//scePrintf("Clearing request %d from entry #%d\n", request_id, i);
return true;
}
}
// Request not found
Dbg_MsgAssert(0, ("Can't clear request: Not found"));
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_init()
{
m_file_handle_index = -1;
m_num_open_requests = 0;
mp_non_aligned_buffer = NULL;
mp_temp_aligned_buffer = NULL;
mp_temp_aligned_buffer_base = NULL;
}
volatile bool CPs2AsyncFileHandle::plat_is_done()
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
return false;
}
volatile bool CPs2AsyncFileHandle::plat_is_busy()
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
return false;
}
bool CPs2AsyncFileHandle::plat_is_eof() const
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_set_priority( int priority )
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket set_packet __attribute__ ((aligned(16)));
set_packet.m_request.m_command = FILEIO_SET;
set_packet.m_request.m_param.m_set.m_file_handle = m_file_handle_index;
set_packet.m_request.m_param.m_set.m_variable = FILEIO_VAR_PRIORITY;
set_packet.m_request.m_param.m_set.m_value = priority;
CFileIOManager::sSendCommand(&set_packet, this, true);
if (m_blocking)
{
WaitForIO();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_set_stream( bool stream )
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket set_packet __attribute__ ((aligned(16)));
set_packet.m_request.m_command = FILEIO_SET;
set_packet.m_request.m_param.m_set.m_file_handle = m_file_handle_index;
set_packet.m_request.m_param.m_set.m_variable = FILEIO_VAR_STREAM;
set_packet.m_request.m_param.m_set.m_value = stream;
CFileIOManager::sSendCommand(&set_packet, this, true);
if (m_blocking)
{
WaitForIO();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_set_destination( EAsyncMemoryType destination )
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket set_packet __attribute__ ((aligned(16)));
set_packet.m_request.m_command = FILEIO_SET;
set_packet.m_request.m_param.m_set.m_file_handle = m_file_handle_index;
set_packet.m_request.m_param.m_set.m_variable = FILEIO_VAR_DESTINATION;
set_packet.m_request.m_param.m_set.m_value = destination;
CFileIOManager::sSendCommand(&set_packet, this, true);
if (m_blocking)
{
WaitForIO();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_set_buffer_size( size_t buffer_size )
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket set_packet __attribute__ ((aligned(16)));
set_packet.m_request.m_command = FILEIO_SET;
set_packet.m_request.m_param.m_set.m_file_handle = m_file_handle_index;
set_packet.m_request.m_param.m_set.m_variable = FILEIO_VAR_BUFFER_SIZE;
set_packet.m_request.m_param.m_set.m_value = buffer_size;
CFileIOManager::sSendCommand(&set_packet, this, true);
if (m_blocking)
{
WaitForIO();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileHandle::plat_set_blocking( bool block )
{
// IOP doesn't need to be notified
}
/******************************************************************/
/* */
/* */
/******************************************************************/
size_t CPs2AsyncFileHandle::plat_load(void *p_buffer)
{
// This function will just get the file size and do one big read
// It is not truly asynchronous now because of the seek wait
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
if (m_position != 0)
{
ShowAsyncInfo("plat_load: Doing seek.\n");
// Now put at the beginning
Seek(0, SEEK_SET);
WaitForIO();
m_current_function = FUNC_LOAD;
}
ShowAsyncInfo("plat_load: Reading into buffer %x.\n", p_buffer);
// And do the read
return plat_read(p_buffer, 1, GetFileSize());
}
/******************************************************************/
/* */
/* */
/******************************************************************/
size_t CPs2AsyncFileHandle::plat_read(void *p_buffer, size_t size, size_t count)
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
//Dbg_MsgAssert((((uint32) p_buffer) & 0xF) == 0, ("Buffer %x needs to be quadword aligned", p_buffer));
// Now send the packet
SFileIORequestPacket read_packet __attribute__ ((aligned(16)));
uint32 non_aligned_cache_start_bytes = 0;
uint32 non_aligned_cache_end_bytes = 0;
// Read in non-aligned bytes first (this is a temp hack)
if (m_mem_destination == MEM_EE)
{
// only look for 16-byte alignment here
bool non_aligned_bytes = ((uint32) p_buffer) & 0xF;
// Also check to see if we aren't cache aligned on either end of a small buffer, since we assume the
// cache alignment problem is at the end of a small buffer.
int non_aligned_cache_bytes = ((uint32) p_buffer) & FILEIO_CACHE_BLOCK_NONALIGN_MASK;
if (non_aligned_cache_bytes)
{
non_aligned_cache_bytes = FILEIO_CACHE_BLOCK_SIZE - non_aligned_cache_bytes;
}
//bool non_aligned_cache_size = ((size * count) - non_aligned_cache_bytes) & FILEIO_CACHE_BLOCK_NONALIGN_MASK;
if (non_aligned_bytes || ((non_aligned_cache_bytes /*|| non_aligned_cache_size*/) && (size * count) < FILEIO_BUFFER_SIZE))
{
Dbg_MsgAssert(!mp_temp_aligned_buffer_base, ("Handling two small reads in succession not implemented yet"));
int aligned_size = ((size * count) + (2 * (FILEIO_CACHE_BLOCK_SIZE - 1))) & FILEIO_CACHE_BLOCK_ALIGN_MASK;
mp_non_aligned_buffer = (uint8 *) p_buffer;
mp_temp_aligned_buffer_base = CPs2AsyncFileLoader::sGetBuffer(aligned_size);
mp_temp_aligned_buffer = (uint8 *) (((uint32) mp_temp_aligned_buffer_base + (FILEIO_CACHE_BLOCK_SIZE - 1)) & FILEIO_CACHE_BLOCK_ALIGN_MASK);
p_buffer = mp_temp_aligned_buffer;
}
else
{
// Now check for cache-alignment problems that will be handled with the messages
non_aligned_cache_start_bytes = (((uint32) p_buffer) & FILEIO_CACHE_BLOCK_NONALIGN_MASK);
if (non_aligned_cache_start_bytes)
{
non_aligned_cache_start_bytes = FILEIO_CACHE_BLOCK_SIZE - non_aligned_cache_start_bytes;
}
non_aligned_cache_end_bytes = ((size * count) - non_aligned_cache_start_bytes) & FILEIO_CACHE_BLOCK_NONALIGN_MASK;
}
}
read_packet.m_request.m_command = FILEIO_READ;
read_packet.m_request.m_param.m_rw.m_file_handle = m_file_handle_index;
read_packet.m_request.m_param.m_rw.m_buffer = p_buffer;
read_packet.m_request.m_param.m_rw.m_size = size * count;
read_packet.m_request.m_param.m_rw.m_non_aligned_start_bytes = non_aligned_cache_start_bytes;
read_packet.m_request.m_param.m_rw.m_non_aligned_end_bytes = non_aligned_cache_end_bytes;
// Mark as busy before sending command
inc_busy_count();
// Garrett (4/18/03): According to the Sony Newsgroups, a FlushCache is not needed if only 1 packet is sent.
// Only the additional packet needs the flush. I think this was helping the issue of non-64 byte aligned
// read buffers. We should try taking this out after the buffers are aligned.
FlushCache(WRITEBACK_DCACHE); // This one is needed, but I think invalidating the cache will work, instead
CFileIOManager::sSendCommand(&read_packet, this, true);
Dbg_Assert(((non_aligned_cache_start_bytes == 0) || (non_aligned_cache_end_bytes == 0)) || ((size * count) >= FILEIO_BUFFER_SIZE));
if (m_blocking)
{
return WaitForIO();
} else {
return 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
size_t CPs2AsyncFileHandle::plat_write(void *p_buffer, size_t size, size_t count)
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
Dbg_MsgAssert((((uint32) p_buffer) & 0xF) == 0, ("Buffer %x needs to be quadword aligned", p_buffer));
// Now send the packet
SFileIORequestPacket write_packet __attribute__ ((aligned(16)));
write_packet.m_request.m_command = FILEIO_WRITE;
write_packet.m_request.m_param.m_rw.m_file_handle = m_file_handle_index;
write_packet.m_request.m_param.m_rw.m_buffer = p_buffer;
write_packet.m_request.m_param.m_rw.m_size = size * count;
// Mark as busy before sending command
inc_busy_count();
FlushCache(WRITEBACK_DCACHE); // This one is needed, but I think invalidating the cache will work, instead
int req_id = CFileIOManager::sSendCommand(&write_packet, this, true);
// Wait for result
CFileIOManager::sWaitRequestCompletion(req_id);
return CFileIOManager::sGetRequestResult(write_packet.m_header.opt);
}
char * CPs2AsyncFileHandle::plat_get_s(char *p_buffer, int maxlen)
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CPs2AsyncFileHandle::plat_seek(long offset, int origin)
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket seek_packet __attribute__ ((aligned(16)));
seek_packet.m_request.m_command = FILEIO_SEEK;
seek_packet.m_request.m_param.m_seek.m_file_handle = m_file_handle_index;
seek_packet.m_request.m_param.m_seek.m_offset = offset;
seek_packet.m_request.m_param.m_seek.m_origin = origin;
// Mark as busy before sending command
inc_busy_count();
CFileIOManager::sSendCommand(&seek_packet, this, true);
if (m_blocking)
{
return WaitForIO();
} else {
return 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2AsyncFileHandle::plat_open(const char *filename)
{
// Init vars
m_position = 0;
// Now send the packet
const char *p_continued_filename = NULL;
SFileIORequestPacket open_packet __attribute__ ((aligned(16)));
open_packet.m_request.m_command = FILEIO_OPEN;
if (Config::CD())
{
if ( !gpHed )
{
return ( false );
}
SHedFile *tempHed = FindFileInHed( filename, gpHed );
if ( !tempHed )
{
//Dbg_MsgAssert( 0,( "File %s cannot be found in Hed file.", filename ));
Dbg_Message( "File %s cannot be found in Hed file.", filename );
return ( false );
}
m_file_size = tempHed->GetFileSize();
open_packet.m_request.m_param.m_open.m_file.m_raw_name.m_sector_number = gWadLSN + (tempHed->Offset / SECTOR_SIZE);
open_packet.m_request.m_param.m_open.m_file.m_raw_name.m_file_size = m_file_size;
open_packet.m_request.m_param.m_open.m_host_read = FILEIO_HOSTOPEN_FALSE;
ShowAsyncInfo("Sending open command for file %s of size %d and offset %d at sector %d\n", filename, m_file_size, tempHed->Offset, gWadLSN + (tempHed->Offset / SECTOR_SIZE));
} else {
//Dbg_MsgAssert(strlen(filename) < FILEIO_MAX_FILENAME_SIZE, ("Can't open file %s: name longer than %d chars", filename, FILEIO_MAX_FILENAME_SIZE - 1));
// Copy filename and check if we need to insert a "host0:" into the name
uint chars_copied = FILEIO_MAX_FILENAME_SIZE - 1;
if (strchr(filename, ':'))
{
strncpy(open_packet.m_request.m_param.m_open.m_file.m_filename, filename, chars_copied);
} else {
//Dbg_MsgAssert(strlen(filename) < (FILEIO_MAX_FILENAME_SIZE - 5), ("Can't open file %s: name longer than %d chars", filename, FILEIO_MAX_FILENAME_SIZE - 6));
chars_copied -= 5;
strcpy(open_packet.m_request.m_param.m_open.m_file.m_filename, "host:");
strncpy(&open_packet.m_request.m_param.m_open.m_file.m_filename[5], filename, chars_copied);
}
// Check for long filename
if (chars_copied < strlen(filename))
{
p_continued_filename = &(filename[chars_copied]);
open_packet.m_request.m_param.m_open.m_host_read = FILEIO_HOSTOPEN_EXTEND_NAME;
}
else
{
open_packet.m_request.m_param.m_open.m_host_read = FILEIO_HOSTOPEN_TRUE;
}
ShowAsyncInfo("Sending host open command for file %s\n", filename);
}
open_packet.m_request.m_param.m_open.m_memory_dest = m_mem_destination;
open_packet.m_request.m_param.m_open.m_buffer_size = m_buffer_size;
open_packet.m_request.m_param.m_open.m_priority = m_priority;
open_packet.m_request.m_param.m_open.m_attributes = 0; // need to define this
// Mark as busy before sending command
inc_busy_count();
uint request_id = CFileIOManager::sSendCommand(&open_packet, this, true);
if (p_continued_filename)
{
Dbg_MsgAssert(strlen(p_continued_filename) < FILEIO_MAX_FILENAME_SIZE, ("Can't open file %s: name longer than %d chars", filename, (FILEIO_MAX_FILENAME_SIZE - 1) * 2));
strcpy(open_packet.m_request.m_param.m_open.m_file.m_filename, p_continued_filename);
open_packet.m_request.m_command = FILEIO_CONT;
#ifdef __NOPT_ASSERT__
uint cont_request_id =
#endif
CFileIOManager::sSendCommand(&open_packet, this, true, request_id);
Dbg_Assert(cont_request_id == request_id);
}
if (m_blocking)
{
return WaitForIO() >= 0;
} else {
// Copy request ID into file handle to use as temp file handle
m_file_handle_index = (int) (FILEIO_TEMP_HANDLE_FLAG | request_id);
return true;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2AsyncFileHandle::raw_open(unsigned int lsn, bool blocking, int priority)
{
Dbg_MsgAssert(!IsBusy(), ("Can't open raw file %d: asynchronous file handle already busy.", lsn));
Dbg_MsgAssert(!mp_pre_file, ("Can't open raw file %d: already open as a PRE file.", lsn));
// Make sure we are using the CD
if (!Config::CD())
{
Dbg_MsgAssert(0, ("Raw Open not supported in host mode"));
return false;
}
m_priority = priority;
m_blocking = blocking;
m_current_function = FUNC_OPEN;
// Init vars
m_position = 0;
// Now send the packet
SFileIORequestPacket open_packet __attribute__ ((aligned(16)));
// Make it the max file size since a the WADs don't keep track of how big they are
m_file_size = MAX_FILE_SIZE;
open_packet.m_request.m_command = FILEIO_OPEN;
open_packet.m_request.m_param.m_open.m_file.m_raw_name.m_sector_number = lsn;
open_packet.m_request.m_param.m_open.m_file.m_raw_name.m_file_size = m_file_size;
open_packet.m_request.m_param.m_open.m_host_read = FILEIO_HOSTOPEN_FALSE;
open_packet.m_request.m_param.m_open.m_memory_dest = m_mem_destination;
open_packet.m_request.m_param.m_open.m_buffer_size = m_buffer_size;
open_packet.m_request.m_param.m_open.m_priority = m_priority;
open_packet.m_request.m_param.m_open.m_attributes = 0; // need to define this
ShowAsyncInfo("Sending raw open command for file of size %d at sector %d\n", m_file_size, lsn);
// Mark as busy before sending command
inc_busy_count();
uint request_id = CFileIOManager::sSendCommand(&open_packet, this, true);
if (m_blocking)
{
return WaitForIO() >= 0;
} else {
// Copy request ID into file handle to use as temp file handle
m_file_handle_index = (int) (FILEIO_TEMP_HANDLE_FLAG | request_id);
return true;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPs2AsyncFileHandle::plat_close()
{
//Dbg_MsgAssert(m_file_handle_index != -1, ("Invalid IOP file handle index: %d", m_file_handle_index));
// Now send the packet
SFileIORequestPacket close_packet __attribute__ ((aligned(16)));
close_packet.m_request.m_command = FILEIO_CLOSE;
close_packet.m_request.m_param.m_close.m_file_handle = m_file_handle_index;
// Mark as busy before sending command
inc_busy_count();
CFileIOManager::sSendCommand(&close_packet, this, true);
m_file_handle_index = -1;
if (m_blocking)
{
return WaitForIO();
} else {
return 0;
}
}
///////////////////////////////////////////////////////////////////////////////////////
CPs2AsyncFileLoader::SAlignBuffer CPs2AsyncFileLoader::s_buffer_list[BUFFER_LIST_SIZE];
//volatile int CPs2AsyncFileLoader::s_free_buffer_list_size = 0;
/******************************************************************/
/* */
/* */
/******************************************************************/
CAsyncFileHandle * CPs2AsyncFileLoader::sRawOpen( unsigned int lsn, bool blocking, int priority )
{
CPs2AsyncFileHandle *p_file_handle = static_cast<CPs2AsyncFileHandle *>(s_get_file_handle());
if (p_file_handle)
{
if (!p_file_handle->raw_open(lsn, blocking, priority))
{
//Dbg_MsgAssert(0, ("Error opening Async file %s", filename));
s_free_file_handle(p_file_handle);
return NULL;
}
return p_file_handle;
}
else
{
Dbg_MsgAssert(0, ("Out of Async handles"));
return NULL;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint8 * CPs2AsyncFileLoader::sGetBuffer( uint size )
{
#if 0
if (size > ALIGN_BUFFER_SIZE)
{
Dbg_Message("sGetBuffer() is trying to allocate %d. Max buffer size is %d", size, ALIGN_BUFFER_SIZE);
Dbg_MsgAssert(0, ("sGetBuffer() is trying to allocate %d. Max buffer size is %d", size, ALIGN_BUFFER_SIZE));
}
if (s_free_buffer_list_size == 0)
{
Dbg_Message("sGetBuffer() out of buffers");
Dbg_MsgAssert(0, ("sGetBuffer() out of buffers"));
}
#endif
//Dbg_Message("***** Getting async buffer of size %d", size);
volatile uint8 *p_buffer = NULL;
// Make sure interrupts are off
DI();
for (int i = 0; i < BUFFER_LIST_SIZE; i++)
{
if ((s_buffer_list[i].m_size >= size) && !s_buffer_list[i].m_used)
{
p_buffer = s_buffer_list[i].mp_buffer;
s_buffer_list[i].m_used = true;
}
}
EI();
Dbg_MsgAssert(p_buffer, ("Couldn't allocate align buffer of size %d", size));
return (uint8 *) p_buffer;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileLoader::sAddBufferToFreeList( uint8 *p_dealloc_buffer )
{
// Make sure interrupts are off
DI();
sIAddBufferToFreeList(p_dealloc_buffer);
EI();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileLoader::sIAddBufferToFreeList( uint8 *p_dealloc_buffer )
{
//scePrintf("***** Freeing async buffer\n");
#if 0 //def __NOPT_ASSERT__
if (s_free_buffer_list_size >= FREE_LIST_SIZE)
{
scePrintf("CPs2AsyncFileLoader::sIAddBufferToFreeList(): Free list full. Tell Garrett.\n");
while (s_free_buffer_list_size >= FREE_LIST_SIZE) // We are basically stuck here
;
}
#endif // __NOPT_ASSERT__
for (int i = 0; i < BUFFER_LIST_SIZE; i++)
{
if (s_buffer_list[i].mp_buffer == p_dealloc_buffer)
{
#ifdef __NOPT_ASSERT__
if (!s_buffer_list[i].m_used)
{
scePrintf("CPs2AsyncFileLoader::sIAddBufferToFreeList(): Freeing a buffer that is already free. Tell Garrett.\n");
while (1)
;
}
#endif // __NOPT_ASSERT__
s_buffer_list[i].m_used = false;
return;
}
}
#ifdef __NOPT_ASSERT__
scePrintf("CPs2AsyncFileLoader::sIAddBufferToFreeList(): Pointer wrong value. Tell Garrett.\n");
while (1)
;
#endif // __NOPT_ASSERT__
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileLoader::sAllocateFreeListBuffers( )
{
int size_chunk = (ALIGN_MAX_BUFFER_SIZE - ALIGN_MIN_BUFFER_SIZE) / (BUFFER_LIST_SIZE - 1);
for (int i = 0; i < BUFFER_LIST_SIZE; i++)
{
int buffer_size = ALIGN_MIN_BUFFER_SIZE + (size_chunk * i);
s_buffer_list[i].mp_buffer = new uint8[buffer_size];
s_buffer_list[i].m_size = buffer_size;
s_buffer_list[i].m_used = false;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CPs2AsyncFileLoader::sDeallocateFreeListBuffers( )
{
Dbg_Assert(0); // We shouldn't be calling this now
#if 0
// Make sure interrupts are off
DI();
for (int i = 0; i < s_free_buffer_list_size; i++)
{
delete [] s_free_buffer_list[i];
s_free_buffer_list[i] = NULL;
}
s_free_buffer_list_size = 0;
EI();
#endif
}
///////////////////////////////////////////////////////////////////////////////////////
sceSifCmdData CFileIOManager::s_cmdbuffer[FILEIO_NUM_COMMAND_HANDLERS];
int CFileIOManager::s_cur_request_id = 0;
CFileIOManager::SOpenRequest CFileIOManager::s_open_requests[NUM_REQUESTS];
int CFileIOManager::s_free_request_index = 0;
/******************************************************************/
/* */
/* CALLBACK */
/* */
/******************************************************************/
void CFileIOManager::s_result_callback(void *p, void *q)
{
SFileIOResultPacket *h = (SFileIOResultPacket *) p;
int request_id = h->m_header.opt;
SOpenRequest *p_request = s_find_request(request_id);
Dbg_MsgAssert(p_request, ("Can't find request id # %d", request_id));
p_request->m_result = h->m_return_value;
p_request->m_done = h->m_done;
//scePrintf( "Got IOP request %d result value %d back with done = %d\n", request_id, p_request->m_result, p_request->m_done );
// Call file handle callback if request is completed
if (p_request->mp_cur_file)
{
// Check if we got any non-aligned data back
if (h->m_non_aligned_data_size > 0)
{
p_request->mp_cur_file->non_cache_aligned_data_copy(h, p_request->m_done);
}
if (p_request->m_done)
{
//p_request->mp_cur_file->io_callback(p_request->mp_cur_file->get_request_function(request_id), p_request->m_result, h->m_return_data);
p_request->mp_cur_file->io_callback(p_request->mp_cur_file->get_request_function(request_id), p_request->m_result, (uint32) h);
p_request->mp_cur_file->clear_request_id(request_id);
}
}
ShowAsyncInfo( "Got IOP request %d result value %d back with done = %d\n", request_id, p_request->m_result, p_request->m_done );
ExitHandler();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CFileIOManager::SOpenRequest * CFileIOManager::s_find_request(int request_id)
{
// Start at the last used index, probably the one used
int index = s_prev_open_index(s_free_request_index);
SOpenRequest *p_start_request = &(s_open_requests[index]);
SOpenRequest *p_request = p_start_request;
do
{
if (p_request->m_id == request_id)
{
return p_request;
}
index = s_prev_open_index(index);
p_request = &(s_open_requests[index]);
} while (p_request != p_start_request);
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CFileIOManager::sInit()
{
// Communicate with the IOP side
sceSifInitRpc(0);
DI();
ShowAsyncInfo( "Setting up Sif Cmd with FileIO IRX...\n" );
sceSifSetCmdBuffer(&s_cmdbuffer[0], FILEIO_NUM_COMMAND_HANDLERS);
sceSifAddCmdHandler(FILEIO_RESULT_COMMAND, s_result_callback, NULL);
EI();
// Clear out pending requests
for (int i = 0; i < NUM_REQUESTS; i++)
{
s_open_requests[i].m_done = true;
s_open_requests[i].m_id = -1;
s_open_requests[i].m_result = -1;
}
s_free_request_index = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CFileIOManager::sSendCommand(SFileIORequestPacket *p_packet, CPs2AsyncFileHandle *p_file, bool wait_for_send, int continuation_request)
{
SOpenRequest *p_request;
if (continuation_request >= 0)
{
p_request = s_find_request(continuation_request);
Dbg_MsgAssert(p_request, ("Can't find open request %d to continue", continuation_request));
// Just in case they didn't wait before
sWaitSendCompletion(p_request->m_id);
}
else
{
p_request = &(s_open_requests[s_free_request_index]);
Dbg_MsgAssert(p_request->m_done, ("Too many open requests"));
s_free_request_index = s_next_open_index(s_free_request_index);
int request_id = s_cur_request_id++;
p_request->m_done = false; // Callback will change it to true
p_request->m_id = request_id;
p_request->mp_cur_file = p_file;
if (p_file)
{
p_file->add_request_id(request_id, p_file->m_current_function, p_packet);
}
p_packet->m_header.opt = request_id;
}
p_request->m_sif_cmd_id = sceSifSendCmd(FILEIO_REQUEST_COMMAND, p_packet, sizeof(SFileIORequestPacket), 0, 0, 0);
if (wait_for_send)
{
sWaitSendCompletion(p_request->m_id);
}
return p_request->m_id;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CFileIOManager::sWaitSendCompletion(int request_id)
{
SOpenRequest *p_request = s_find_request(request_id);
Dbg_MsgAssert(p_request, ("Can't find request id # %d", request_id));
while(sceSifDmaStat(p_request->m_sif_cmd_id) >= 0)
;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CFileIOManager::sWaitRequestCompletion(int request_id)
{
SOpenRequest *p_request = s_find_request(request_id);
Dbg_MsgAssert(p_request, ("Can't find request id # %d", request_id));
while (!p_request->CommandDone())
;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
volatile bool CFileIOManager::sCommandDone(int request_id)
{
SOpenRequest *p_request = s_find_request(request_id);
Dbg_MsgAssert(p_request, ("Can't find request id # %d", request_id));
return p_request->m_done;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CFileIOManager::sGetRequestResult(int request_id)
{
SOpenRequest *p_request = s_find_request(request_id);
Dbg_MsgAssert(p_request, ("Can't find request id # %d", request_id));
return p_request->m_result;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAsyncFileLoader::s_plat_init()
{
for (int i = 0; i < MAX_FILE_HANDLES; i++)
{
if (s_file_handles[i])
{
s_file_handles[i]->init();
}
else
{
s_file_handles[i] = new CPs2AsyncFileHandle;
}
}
// Allocate EE align buffers
CPs2AsyncFileLoader::sAllocateFreeListBuffers();
// Init the FileIO Manager
CFileIOManager::sInit();
// Now send the first packet
SFileIORequestPacket init_packet __attribute__ ((aligned(16)));
init_packet.m_request.m_command = FILEIO_INIT;
init_packet.m_request.m_param.m_init.m_buffer_size = DEFAULT_BUFFER_SIZE;
init_packet.m_request.m_param.m_init.m_priority = DEFAULT_ASYNC_PRIORITY;
init_packet.m_request.m_param.m_init.m_memory_dest = DEFAULT_MEMORY_TYPE;
init_packet.m_request.m_param.m_init.m_init_cd_device = Config::CD();
int req_id = CFileIOManager::sSendCommand(&init_packet, NULL, true);
Dbg_Message("Sending first init command to fileio.irx: waiting for completion");
// Wait for result (no async inits)
CFileIOManager::sWaitRequestCompletion(req_id);
Dbg_Message("Sent first init command to fileio.irx.");
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAsyncFileLoader::s_plat_cleanup()
{
for (int i = 0; i < MAX_FILE_HANDLES; i++)
{
if (s_file_handles[i])
{
delete s_file_handles[i];
s_file_handles[i] = NULL;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CAsyncFileLoader::s_plat_async_supported()
{
// Works on the PS2
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CAsyncFileLoader::s_plat_exist(const char *filename)
{
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAsyncFileLoader::s_plat_update(void)
{
//// Free any buffers let go during an interrupt
//CPs2AsyncFileLoader::sDeallocateFreeListBuffers();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAsyncFileLoader::s_plat_swap_callback_list()
{
// We must disable interrupts here so that the IO interrupts don't change things underneath us.
DI();
s_cur_callback_list_index = s_cur_callback_list_index ^ 1; // Swap Indexes
s_new_io_completion = false; // And clear flag
#ifdef __NOPT_ASSERT__
bool new_list_clear = s_num_callbacks[s_cur_callback_list_index] == 0;
#endif // __NOPT_ASSERT__
// And re-enable interrupts
EI();
Dbg_MsgAssert(new_list_clear, ("Async IO swapped callback list isn't empty"));
}
}