thug/Code/Sys/File/ngps/FileIO/command.c
2016-02-14 08:39:12 +11:00

1618 lines
47 KiB
C

/* FileIO -- Converted from Sony samples -- Garrett Oct 2002 */
#include <kernel.h>
#include <libcdvd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include <sif.h>
#include <sifrpc.h>
#include <sifcmd.h>
#include <thread.h>
#include "fileio.h"
#include "fileio_iop.h"
// ================================================================
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
// FileIO prototypes
static int FileIO_GetDescriptor(int memory_destination, int buffer_size);
static int FileIO_FindFileHandleIndex(volatile unsigned int *p_file_handle_index);
static void FileIO_Init(int priority, int buffer_size, short memory_destination, short init_cd_device);
static void FileIO_Open(int sector_num, int file_size, int memory_destination, int buffer_size, int priority, int attributes);
static void FileIO_HostOpen(char *p_filename, int memory_destination, int buffer_size, int priority, int attributes,
FileIOHostOpen open_type, SFileIORequest *p_cont_request);
static void FileIO_Close(volatile unsigned int *p_file_handle_index);
static void FileIO_Read(SFileIORequest *p_request, volatile unsigned int *p_file_handle_index, void *p_buffer, int size, int non_aligned_start_bytes, int non_aligned_end_bytes);
static void FileIO_Write(SFileIORequest *p_request, volatile unsigned int *p_file_handle_index, void *p_buffer, int size, int non_aligned_start_bytes, int non_aligned_end_bytes);
static void FileIO_Seek(volatile unsigned int *p_file_handle_index, int offset, int origin);
static void FileIO_Set(volatile unsigned int *p_file_handle_index, FileIOVariable variable, int value);
// Debug info
#define SHOW_FILEIO_INFO 0
#if SHOW_FILEIO_INFO
#define ShowFileIOInfo(A...) Kprintf(##A)
#else
#define ShowFileIOInfo(A...)
#endif
unsigned int gThid = 0;
unsigned int gSem = 0;
unsigned int gCmdSem = 0;
// Defaults
int gDefaultPriority;
int gDefaultBufferSize;
int gDefaultMemoryDestination;
// File handles and buffers
SFileIOHandle gFileHandle[FILEIO_MAX_HANDLERS];
unsigned char gFileBuffer[FILEIO_MAX_BUFFERS][FILEIO_BUFFER_SIZE];
unsigned char * gFileBufferList[FILEIO_MAX_BUFFERS];
int gFreeFileBufferIndex;
// Device status var
static SFileIODevice sFileIODevices[NUM_DEVICE_TYPES];
static SFileIOResultPacket s_result_packet;
static SRequestStatus s_cur_command_status;
static void ServiceCurrentFileHandle(int resend);
static int StartCdRead(int start_sector, int num_sectors, void *p_buffer);
static void SendNowaitResult();
static int GetResultPacketSize(SFileIOResultPacket *p_packet);
static void AppendTask(SFileIODevice *p_device, SFileIOTask *p_task);
static void InsertTask(SFileIODevice *p_device, SFileIOTask *p_task);
static void RemoveTask(SFileIODevice *p_device, SFileIOTask *p_task);
static int AppendContRequest(SFileIOTask *p_task);
//
// Callback
static void cd_callback(int arg)
{
void *p_ee_addr = NULL, *p_iop_addr = NULL;
int block_size = 0;
SFileIODevice *p_device = &sFileIODevices[DEVICE_CD];
SFileIOHandle *p_file = p_device->mp_file_handle;
int resend = FALSE;
// Lame hack to make sure we issued the sceCd call, not some legacy code
if (!p_device->m_in_use)
{
ShowFileIOInfo("Got CD callback even though we didn't issue a command\n");
return;
}
// Wait for previous transfer to finish before we try to read any more (maybe we shouldn't do this in a callback)
if (p_file->m_flags & FILEIO_HANDLE_PREV_DMA)
{
while(sceSifDmaStat(p_file->m_last_dma_id) >= 0)
;
}
// Clear out data transfer size
s_result_packet.m_non_aligned_data_size = 0;
switch (p_file->m_cur_function)
{
case FILEIO_FUNCTION_READ:
// Check that we got the correct arg back. Re-send command if not.
if ((arg != SCECdFuncRead) && (arg != SCECdFuncSeek))
{
resend = TRUE;
break;
}
// We probably won't set this for an IOP memory operation
s_result_packet.m_byte_transfer = p_file->m_bytes_processing;
// Figure out if we are done before calling ServiceCurrentFileHandle()
s_result_packet.m_done = (p_file->m_bytes_to_process == 0);
s_result_packet.m_header.opt = p_file->m_request_id;
s_result_packet.m_return_value = p_file->m_return_value;
s_result_packet.m_return_data = p_file->m_return_data;
// Do we need to transfer to EE?
if (p_file->m_flags & FILEIO_HANDLE_EE_MEMORY)
{
p_iop_addr = p_device->mp_buffer[p_device->m_buffer_index];
p_device->m_buffer_index ^= 1;
p_ee_addr = p_file->mp_dest_buffer;
block_size = p_file->m_bytes_processing;
// Check non-alignment
if (p_file->m_non_aligned_start_bytes)
{
s_result_packet.m_non_aligned_data_size = p_file->m_non_aligned_start_bytes;
memcpy(s_result_packet.m_non_aligned_data, p_iop_addr, p_file->m_non_aligned_start_bytes);
p_file->m_non_aligned_start_bytes = 0;
//if (s_result_packet.m_done && p_file->m_non_aligned_end_bytes)
//{
// Kprintf("Have both non-aligned data at beginning and end of buffer\n");
//}
}
else if (s_result_packet.m_done && p_file->m_non_aligned_end_bytes)
{
s_result_packet.m_non_aligned_data_size = p_file->m_non_aligned_end_bytes;
memcpy(s_result_packet.m_non_aligned_data, p_iop_addr + (block_size - p_file->m_non_aligned_end_bytes), p_file->m_non_aligned_end_bytes);
}
}
// Advance dest pointer
p_file->mp_dest_buffer = p_file->mp_dest_buffer + block_size;
break;
case FILEIO_FUNCTION_OPEN:
case FILEIO_FUNCTION_SEEK:
s_result_packet.m_byte_transfer = 0;
s_result_packet.m_done = TRUE;
s_result_packet.m_return_value = p_file->m_return_value;
s_result_packet.m_return_data = p_file->m_return_data;
s_result_packet.m_header.opt = s_cur_command_status.m_request_id;
p_file->m_cur_function = FILEIO_FUNCTION_IDLE;
break;
default:
// Something went wrong here
ShowFileIOInfo("Got cd callback from an unexpected function: %d\n", p_file->m_cur_function);
s_result_packet.m_byte_transfer = 0;
s_result_packet.m_done = TRUE;
s_result_packet.m_return_value = -1;
s_result_packet.m_return_data = -1;
s_result_packet.m_header.opt = s_cur_command_status.m_request_id;
break;
}
if (!resend)
{
p_file->m_flags |= FILEIO_HANDLE_PREV_DMA;
p_file->m_last_dma_id = isceSifSendCmd(FILEIO_RESULT_COMMAND, &s_result_packet, GetResultPacketSize(&s_result_packet), p_iop_addr, p_ee_addr, block_size);
}
ShowFileIOInfo("FileIO cd callback: sent result %d back from %x to %x of size %d with data %x %x %x %x and arg %x error %d resend %d\n", s_result_packet.m_return_value, p_iop_addr, p_ee_addr, block_size,
((unsigned int *) p_iop_addr)[0],
((unsigned int *) p_iop_addr)[1],
((unsigned int *) p_iop_addr)[2],
((unsigned int *) p_iop_addr)[3],
arg, sceCdGetError(), resend );
// Check to see if we need to send out more CD commands
ServiceCurrentFileHandle(resend);
// Wake up the dispatch thread
iSignalSema(gCmdSem);
}
// Can be called from both from outside and within a CD callback
static void ServiceCurrentFileHandle(int resend)
{
int sectors_to_read;
SFileIODevice *p_device = &sFileIODevices[DEVICE_CD];
SFileIOHandle *p_file = p_device->mp_file_handle;
// Read parameters: need to save in case of resend
static int cur_sector;
static int num_sectors;
static void *p_local_buffer;
if (resend)
{
ShowFileIOInfo("ServiceCurrentFileHandle %x: Resending read of %d sectors starting at %d to %x with %d bytes left\n", p_file, num_sectors, cur_sector, p_local_buffer, p_file->m_bytes_to_process);
StartCdRead(cur_sector, num_sectors, p_local_buffer);
return;
}
// Right now, this only does something with reads
if (p_file->m_cur_function != FILEIO_FUNCTION_READ)
{
// We're done
p_file->m_flags &= ~FILEIO_HANDLE_BUSY;
p_device->m_in_use = FALSE;
return;
}
sectors_to_read = (p_file->m_bytes_to_process + SECTOR_SIZE - 1) / SECTOR_SIZE;
// Check if we need to seek first
if (p_file->m_cur_sector != p_device->m_cur_sector)
{
p_device->m_cur_sector = p_file->m_cur_sector;
p_device->m_cur_position = p_file->m_cur_position;
// We don't need to seek since the read does it for us.
//sceCdSeek(p_file->m_cur_sector);
//ShowFileIOInfo("ServiceCurrentFileHandle %x: Seeking to sector %d\n", p_file, p_file->m_cur_sector);
//return;
}
if (sectors_to_read)
{
cur_sector = p_file->m_cur_sector;
if (p_file->m_flags & FILEIO_HANDLE_EE_MEMORY)
{
p_local_buffer = p_device->mp_buffer[p_device->m_buffer_index];
num_sectors = MIN(FILEIO_BUFFER_SECTORS, sectors_to_read);
}
else
{
// Note that we don't handle the last sector properly, which most likely won't be
// filled (and would overwrite the output buffer).
p_local_buffer = p_file->mp_dest_buffer;
num_sectors = sectors_to_read;
}
// Advance the file stats before the read call, since, in theory, the read could call the
// callback immediately
p_file->m_cur_sector += num_sectors;
p_file->m_cur_position += num_sectors * SECTOR_SIZE;
p_file->m_bytes_processing = MIN(num_sectors * SECTOR_SIZE, p_file->m_bytes_to_process);
p_file->m_bytes_to_process = MAX(p_file->m_bytes_to_process - p_file->m_bytes_processing, 0);
ShowFileIOInfo("ServiceCurrentFileHandle %x: Reading %d sectors starting at %d to %x with %d bytes left\n", p_file, num_sectors, cur_sector, p_local_buffer, p_file->m_bytes_to_process);
p_device->m_cur_sector = p_file->m_cur_sector;
p_device->m_cur_position = p_file->m_cur_position;
StartCdRead(cur_sector, num_sectors, p_local_buffer);
} else {
// We're done
p_file->m_flags &= ~FILEIO_HANDLE_BUSY;
p_device->m_in_use = FALSE;
// Send message to EE that we are done
}
}
#define NUM_WAIT_CLICKS 1000
static int StartCdRead(int start_sector, int num_sectors, void *p_buffer)
{
int result;
sceCdRMode mode;
int retries = 0;
static int wait_read = 0;
if (wait_read)
{
ShowFileIOInfo("Got callback while waiting to resend\n");
return 0;
}
wait_read = 1;
mode.trycount = 255;
mode.spindlctrl = SCECdSpinNom;
mode.datapattern = SCECdSecS2048;
mode.pad = 0;
do
{
//if (sceCdSync( 1 ))
// ShowFileIOInfo("Sync isn't ready before the CD read\n");
result = sceCdRead(start_sector, num_sectors, p_buffer, &mode);
if (result == 0)
{
int i, j = 0;
Kprintf("sceCdRead() didn't start. Returned %d with error %d. Retrying...\n", result, sceCdGetError());
sceCdSync( 0 );
do
{
for ( i = 0; i < NUM_WAIT_CLICKS; i++ )
;
if ( j++ > NUM_WAIT_CLICKS )
{
j = 0;
}
} while ( j != 0 );
while(sceCdDiskReady(0)!=SCECdComplete)
;
//sceCdSeek(0);
//sceCdSync( 0 );
//result = 1;
retries++;
}
} while ((result == 0) && (retries <= 15)); // Need to eventually abort this if retries get too high
wait_read = 0;
return result;
}
// Returns packet size of result, rounded up to a 16-byte chunk
static int GetResultPacketSize(SFileIOResultPacket *p_packet)
{
unsigned int base_size = ((unsigned int) &(p_packet->m_non_aligned_data[0]) - (unsigned int) p_packet);
return ((base_size + p_packet->m_non_aligned_data_size) + 0xf) & ~0xf;
}
////////////////////////////////
// Tries to find the real file handle index from the open request ID
static int FileIO_FindFileHandleIndex(volatile unsigned int *p_file_handle_index)
{
int fd;
int open_request_id = (int) (*p_file_handle_index & ~FILEIO_TEMP_HANDLE_FLAG);
for (fd = 0; fd < FILEIO_MAX_HANDLERS; fd++)
{
if (gFileHandle[fd].m_open_request_id == open_request_id)
{
ShowFileIOInfo("FileIO: converting open request id %d to file handle index %d\n", open_request_id, fd);
*p_file_handle_index = fd;
return TRUE;
}
}
ShowFileIOInfo("FileIO: can't convert open request id %d to file handle index\n", open_request_id);
return FALSE;
}
////////////////////////////////
// Init
static void FileIO_Init(int priority, int buffer_size, short memory_destination, short init_cd_device)
{
int detected_disk_type;
int i;
printf("Starting FileIO_Init\n");
sFileIODevices[DEVICE_CD].m_in_use = FALSE;
sFileIODevices[DEVICE_CD].mp_file_handle = NULL;
// Init drive
if (init_cd_device)
{
#if 0 // Doesn't seem to be necessary, since we already do this on the EE
sceCdInit(SCECdINIT);
sceCdMmode(SCECdDVD);
// find the disk type, this might be different from what we intialized to
printf("FileIO: sceCdGetDiskType ");
detected_disk_type= sceCdGetDiskType();
switch(detected_disk_type)
{
case SCECdIllgalMedia:
printf("Disk Type= IllgalMedia\n"); break;
case SCECdPS2DVD:
printf("Disk Type= PlayStation2 DVD\n"); break;
case SCECdPS2CD:
printf("Disk Type= PlayStation2 CD\n"); break;
case SCECdPS2CDDA:
printf("Disk Type= PlayStation2 CD with CDDA\n"); break;
case SCECdPSCD:
printf("Disk Type= PlayStation CD\n"); break;
case SCECdPSCDDA:
printf("Disk Type= PlayStation CD with CDDA\n"); break;
case SCECdDVDV:
printf("Disk Type= DVD video\n"); break;
case SCECdCDDA:
printf("Disk Type= CD-DA\n"); break;
case SCECdDETCT:
printf("Working\n"); break;
case SCECdNODISC:
printf("Disk Type= No Disc\n"); break;
default:
printf("Disk Type= OTHER DISK\n"); break;
}
// If disk type has changed to a CD, then need to re-initialize it
if (detected_disk_type == SCECdPS2CD)
{
#if __DVD_ONLY__
printf( "*** ERROR - CD Detected, needs DVD.\n" );
#else
printf( "reinitializing for Ps2CD\n" );
sceCdMmode(SCECdCD);
printf( "done reinitializing\n" );
#endif
}
#endif
// Set up callback
sceCdCallback(cd_callback);
}
// Set default parameters
gDefaultPriority = priority;
gDefaultBufferSize = buffer_size;
gDefaultMemoryDestination = memory_destination;
// Init the file handles and buffers
for (i = 0; i < FILEIO_MAX_HANDLERS; i++)
{
gFileHandle[i].m_flags = 0; // Neither busy nor reserved
//gFileHandle[i].mp_buffer[0] = NULL;
//gFileHandle[i].mp_buffer[1] = NULL;
//gFileHandle[i].m_buffer_index = -1;
gFileHandle[i].mp_dest_buffer = NULL;
gFileHandle[i].m_device_type = DEVICE_UNKNOWN;
gFileHandle[i].m_buffer_size = buffer_size;
gFileHandle[i].m_host_fd = -1;
gFileHandle[i].m_priority = priority;
gFileHandle[i].m_stream = FALSE;
gFileHandle[i].m_start_sector = 0;
gFileHandle[i].m_cur_sector = 0;
gFileHandle[i].m_cur_position = 0;
gFileHandle[i].m_file_size = 0;
gFileHandle[i].m_open_request_id= -1;
}
for (i = 0; i < FILEIO_MAX_BUFFERS; i++)
{
gFileBufferList[i] = gFileBuffer[i];
}
gFreeFileBufferIndex = 0;
// Allocate device buffers
for (i = 0; i < DEVICE_UNKNOWN; i++)
{
if ((gFreeFileBufferIndex + 1) < FILEIO_MAX_BUFFERS)
{
// Use buffer size in the future
sFileIODevices[i].mp_buffer[0] = gFileBufferList[gFreeFileBufferIndex++];
sFileIODevices[i].mp_buffer[1] = gFileBufferList[gFreeFileBufferIndex++];
sFileIODevices[i].m_buffer_index = 0;
}
else
{
// Can't allocate
printf("Out of fileio memory buffers\n");
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
}
printf("Done FileIO_Init\n");
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = TRUE;
return;
}
////////////////////////////////
// GetDescriptor
static int FileIO_GetDescriptor(int memory_destination, int buffer_size)
{
int i;
for (i = 0; i < FILEIO_MAX_HANDLERS; i++)
{
if (!(gFileHandle[i].m_flags & FILEIO_HANDLE_RESERVED))
{
gFileHandle[i].m_buffer_size = buffer_size;
if (memory_destination == MEM_EE)
{
gFileHandle[i].m_flags |= FILEIO_HANDLE_EE_MEMORY;
#if 0
if ((gFreeFileBufferIndex + 1) < FILEIO_MAX_BUFFERS)
{
// Use buffer size in the future
gFileHandle[i].mp_buffer[0] = gFileBufferList[gFreeFileBufferIndex++];
gFileHandle[i].mp_buffer[1] = gFileBufferList[gFreeFileBufferIndex++];
gFileHandle[i].m_buffer_index = 0;
}
else
{
// Can't open
printf("Out of fileio memory buffers\n");
return -1;
}
#endif
}
else
{
gFileHandle[i].m_flags &= ~FILEIO_HANDLE_EE_MEMORY;
#if 0
gFileHandle[i].mp_buffer[0] = NULL;
gFileHandle[i].mp_buffer[1] = NULL;
gFileHandle[i].m_buffer_index = -1;
#endif
}
gFileHandle[i].m_flags |= FILEIO_HANDLE_RESERVED;
return i;
}
}
// Couldn't find a free descriptor
printf("Out of fileio file descriptors\n");
return -1;
}
////////////////////////////////
// Open
static void FileIO_Open(int sector_num, int file_size, int memory_destination, int buffer_size, int priority, int attributes)
{
int fd = FileIO_GetDescriptor(memory_destination, buffer_size);
if (fd >= 0)
{
// Init the handle itself
gFileHandle[fd].m_device_type = DEVICE_CD;
gFileHandle[fd].mp_dest_buffer = NULL;
gFileHandle[fd].m_host_fd = -1;
gFileHandle[fd].m_priority = priority;
gFileHandle[fd].m_stream = FALSE;
gFileHandle[fd].m_start_sector = sector_num;
gFileHandle[fd].m_cur_sector = sector_num;
gFileHandle[fd].m_cur_position = 0;
gFileHandle[fd].m_file_size = file_size;
gFileHandle[fd].m_open_request_id= s_cur_command_status.m_request_id;
gFileHandle[fd].mp_blocked_request = NULL;
gFileHandle[fd].m_flags &= ~FILEIO_HANDLE_BUSY;
gFileHandle[fd].m_cur_function = FILEIO_FUNCTION_IDLE;
// Don't do seek, just return
gFileHandle[fd].m_return_value = fd;
gFileHandle[fd].m_return_data = file_size;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.mp_file_handle = &(gFileHandle[fd]);
s_cur_command_status.m_return_value = fd;
s_cur_command_status.m_return_data = file_size;
ShowFileIOInfo("Opened file using handle %d\n", fd);
} else {
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
}
////////////////////////////////
// HostOpen
static void FileIO_HostOpen(char *p_filename, int memory_destination, int buffer_size, int priority, int attributes,
FileIOHostOpen open_type, SFileIORequest *p_cont_request)
{
int fd, host_fd;
char full_filename[FILEIO_MAX_FILENAME_SIZE * 2];
strcpy(full_filename, p_filename);
if (open_type == FILEIO_HOSTOPEN_EXTEND_NAME)
{
if (p_cont_request)
{
strcat(full_filename, p_cont_request->m_param.m_open.m_file.m_filename);
ShowFileIOInfo("FileIO HostOpen: opening extended filename %s\n", full_filename);
}
else
{
ShowFileIOInfo("FileIO HostOpen: waiting for rest of filename for %s\n", p_filename);
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
}
host_fd = open(full_filename, O_RDONLY);
if (host_fd >= 0)
{
// Find file size
int file_size = lseek(host_fd, 0, SEEK_END);
lseek(host_fd, 0, SEEK_SET);
fd = FileIO_GetDescriptor(memory_destination, buffer_size);
if (fd >= 0)
{
// Init the handle itself
gFileHandle[fd].m_device_type = DEVICE_HOST;
gFileHandle[fd].mp_dest_buffer = NULL;
gFileHandle[fd].m_priority = priority;
gFileHandle[fd].m_stream = FALSE;
gFileHandle[fd].m_start_sector = -1;
gFileHandle[fd].m_cur_sector = -1;
gFileHandle[fd].m_cur_position = 0;
gFileHandle[fd].m_file_size = file_size;
gFileHandle[fd].m_open_request_id= s_cur_command_status.m_request_id;
gFileHandle[fd].mp_blocked_request = NULL;
gFileHandle[fd].m_flags &= ~FILEIO_HANDLE_BUSY;
gFileHandle[fd].m_cur_function = FILEIO_FUNCTION_IDLE;
// Do a open
gFileHandle[fd].m_host_fd = host_fd;
gFileHandle[fd].m_return_value = fd;
gFileHandle[fd].m_return_data = file_size;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.mp_file_handle = &(gFileHandle[fd]);
s_cur_command_status.m_return_value = fd;
s_cur_command_status.m_return_data = file_size;
return;
} else {
printf("Can't get free descriptor for host open of %s\n", full_filename);
close(host_fd);
}
} else {
printf("Can't open file %s on host\n", full_filename);
}
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
////////////////////////////////
// Close
static void FileIO_Close(volatile unsigned int *p_file_handle_index)
{
SFileIOHandle *p_file;
//int i, j;
// See if we have the correct index, and if we can't get it, return
if ((*p_file_handle_index & FILEIO_TEMP_HANDLE_FLAG) && !FileIO_FindFileHandleIndex(p_file_handle_index))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
p_file = &(gFileHandle[*p_file_handle_index]);
if (p_file->m_flags & FILEIO_HANDLE_RESERVED)
{
s_cur_command_status.mp_file_handle = p_file;
// Can't close if we're busy
if (p_file->m_flags & FILEIO_HANDLE_BUSY)
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
// Check if a host handle
if (p_file->m_host_fd >= 0)
{
close(p_file->m_host_fd);
}
#if 0
// Check if buffer needs freeing
if (p_file->mp_buffer[0])
{
for (i = 0; i < FILEIO_MAX_BUFFERS; i++)
{
for (j = 0; j < 2; j++)
{
if (p_file->mp_buffer[j] == gFileBufferList[i])
{
// Found it, exchange it with last used buffer
gFileBufferList[i] = gFileBufferList[--gFreeFileBufferIndex];
gFileBufferList[gFreeFileBufferIndex] = p_file->mp_buffer[j];
p_file->mp_buffer[j] = NULL;
}
}
}
p_file->m_buffer_index = -1;
}
#endif
p_file->m_flags &= ~FILEIO_HANDLE_RESERVED;
ShowFileIOInfo("CLOSE: handle %d open and not busy\n", *p_file_handle_index);
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = TRUE;
return;
}
// Handle wasn't open
ShowFileIOInfo("CLOSE: handle %d not open\n", *p_file_handle_index);
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = FALSE;
return;
}
////////////////////////////////
// Read
static void FileIO_Read(SFileIORequest *p_request, volatile unsigned int *p_file_handle_index, void *p_buffer, int size, int non_aligned_start_bytes, int non_aligned_end_bytes)
{
SFileIOHandle *p_file;
int host_read;
int bytes_to_read;
// See if we have the correct index, and if we can't get it, return
if ((*p_file_handle_index & FILEIO_TEMP_HANDLE_FLAG) && !FileIO_FindFileHandleIndex(p_file_handle_index))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
p_file = &(gFileHandle[*p_file_handle_index]);
host_read = (p_file->m_host_fd >= 0);
s_cur_command_status.mp_file_handle = p_file;
// Can't add additional read if we're already busy
if ((p_file->m_flags & FILEIO_HANDLE_BUSY) && !(p_file->mp_blocked_request && (p_file->mp_blocked_request == p_request)))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
// Check to make sure device is free
if (host_read)
{
// Nothing to check for now
}
else
{
if (sFileIODevices[DEVICE_CD].m_in_use)
{
// Mark file handle as blocked
p_file->mp_blocked_request = p_request;
p_file->m_flags |= FILEIO_HANDLE_BUSY;
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
else
{
// Clear blocked status
p_file->mp_blocked_request = NULL;
p_file->m_flags &= ~FILEIO_HANDLE_BUSY;
}
}
// We won't support non sector aligned reads now
if (!host_read && (p_file->m_cur_position & (SECTOR_SIZE - 1)))
{
printf("Can't read from position %d because it isn't on a sector boundary\n", p_file->m_cur_position);
p_file->m_cur_function = FILEIO_FUNCTION_IDLE;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
p_file->m_bytes_to_process = MIN(size, p_file->m_file_size - p_file->m_cur_position);
p_file->m_bytes_processing = 0;
p_file->m_non_aligned_start_bytes = non_aligned_start_bytes;
p_file->m_non_aligned_end_bytes = non_aligned_end_bytes;
p_file->m_request_id = s_cur_command_status.m_request_id;
// Set destination buffer (EE or IOP address) and size
p_file->mp_dest_buffer = p_buffer;
bytes_to_read = p_file->m_bytes_to_process;
// Do the actual read
if (host_read)
{
SFileIODevice *p_device = &sFileIODevices[DEVICE_HOST];
// We should really be looking for the old one and making sure it is done
p_file->m_flags &= ~FILEIO_HANDLE_PREV_DMA;
// Just do the read here until we set up a separate thread
while (p_file->m_bytes_to_process)
{
void *p_ee_addr = NULL, *p_iop_addr = NULL;
int block_size = 0;
int num_bytes;
void *p_local_buffer;
if (p_file->m_flags & FILEIO_HANDLE_EE_MEMORY)
{
p_local_buffer = p_device->mp_buffer[p_device->m_buffer_index];
num_bytes = MIN(FILEIO_BUFFER_SIZE, p_file->m_bytes_to_process);
}
else
{
p_local_buffer = p_file->mp_dest_buffer;
num_bytes = p_file->m_bytes_to_process;
}
// Advance the file stats before the read call, since, in theory, the read could call the
// callback immediately
p_file->m_cur_position += num_bytes;
p_file->m_bytes_processing = num_bytes;
p_file->m_bytes_to_process = p_file->m_bytes_to_process - p_file->m_bytes_processing;
ShowFileIOInfo("Host read %x: Reading %d bytes to %x with %d bytes left\n", p_file, num_bytes, p_local_buffer, p_file->m_bytes_to_process);
read(p_file->m_host_fd, p_local_buffer, num_bytes);
// Wait for previous transfer to finish before we try to read any more (maybe we shouldn't do this in a callback)
if (p_file->m_flags & FILEIO_HANDLE_PREV_DMA)
{
while(sceSifDmaStat(p_file->m_last_dma_id) >= 0)
;
}
// We probably won't set this for an IOP memory operation
s_result_packet.m_byte_transfer = p_file->m_bytes_processing;
// Figure out if we are done before calling ServiceCurrentFileHandle()
s_result_packet.m_done = (p_file->m_bytes_to_process == 0);
s_result_packet.m_header.opt = p_file->m_request_id;
s_result_packet.m_return_value = bytes_to_read;
s_result_packet.m_non_aligned_data_size = 0;
// Do we need to transfer to EE?
if (p_file->m_flags & FILEIO_HANDLE_EE_MEMORY)
{
p_iop_addr = p_local_buffer;
p_device->m_buffer_index ^= 1;
p_ee_addr = p_file->mp_dest_buffer;
block_size = p_file->m_bytes_processing;
// Check non-alignment
if (p_file->m_non_aligned_start_bytes)
{
s_result_packet.m_non_aligned_data_size = p_file->m_non_aligned_start_bytes;
memcpy(s_result_packet.m_non_aligned_data, p_iop_addr, p_file->m_non_aligned_start_bytes);
p_file->m_non_aligned_start_bytes = 0;
}
else if (s_result_packet.m_done && p_file->m_non_aligned_end_bytes)
{
s_result_packet.m_non_aligned_data_size = p_file->m_non_aligned_end_bytes;
memcpy(s_result_packet.m_non_aligned_data, p_iop_addr + (block_size - p_file->m_non_aligned_end_bytes), p_file->m_non_aligned_end_bytes);
}
}
// Advance dest pointer
p_file->mp_dest_buffer = p_file->mp_dest_buffer + block_size;
p_file->m_flags |= FILEIO_HANDLE_PREV_DMA;
p_file->m_last_dma_id = sceSifSendCmd(FILEIO_RESULT_COMMAND, &s_result_packet, GetResultPacketSize(&s_result_packet), p_iop_addr, p_ee_addr, block_size);
ShowFileIOInfo("FileIO host read: sent result %d back from %x to %x of size %d\n", s_result_packet.m_return_value, p_iop_addr, p_ee_addr, block_size);
}
s_cur_command_status.m_request_state = REQUEST_PROCESSING; // Don't want to send another result packet
p_file->m_return_value = bytes_to_read;
}
else
{
// We should really be looking for the old one and making sure it is done
p_file->m_flags &= ~FILEIO_HANDLE_PREV_DMA;
// Mark that we are using the CD
p_file->m_flags |= FILEIO_HANDLE_BUSY;
sFileIODevices[DEVICE_CD].m_in_use = TRUE;
sFileIODevices[DEVICE_CD].mp_file_handle = p_file;
p_file->m_cur_function = FILEIO_FUNCTION_READ;
p_file->m_return_value = p_file->m_bytes_to_process;
s_cur_command_status.m_request_state = REQUEST_PROCESSING;
ServiceCurrentFileHandle(FALSE);
}
return;
}
////////////////////////////////
// Write
static void FileIO_Write(SFileIORequest *p_request, volatile unsigned int *p_file_handle_index, void *p_buffer, int size, int non_aligned_start_bytes, int non_aligned_end_bytes)
{
SFileIOHandle *p_file;
// See if we have the correct index, and if we can't get it, return
if ((*p_file_handle_index & FILEIO_TEMP_HANDLE_FLAG) && !FileIO_FindFileHandleIndex(p_file_handle_index))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
p_file = &(gFileHandle[*p_file_handle_index]);
s_cur_command_status.mp_file_handle = p_file;
// Can't write if we're already busy
if ((p_file->m_flags & FILEIO_HANDLE_BUSY) && !(p_file->mp_blocked_request && (p_file->mp_blocked_request == p_request)))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
////////////////////////////////
// Seek
static void FileIO_Seek(volatile unsigned int *p_file_handle_index, int offset, int origin)
{
int new_position;
SFileIOHandle *p_file;
// See if we have the correct index, and if we can't get it, return
if ((*p_file_handle_index & FILEIO_TEMP_HANDLE_FLAG) && !FileIO_FindFileHandleIndex(p_file_handle_index))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
p_file = &(gFileHandle[*p_file_handle_index]);
s_cur_command_status.mp_file_handle = p_file;
// Can't start seek if we're already busy
if (p_file->m_flags & FILEIO_HANDLE_BUSY)
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
// Do the adjustments
switch (origin)
{
case SEEK_CUR:
new_position = p_file->m_cur_position + offset;
break;
case SEEK_SET:
new_position = offset;
break;
case SEEK_END:
new_position = p_file->m_file_size - offset;
break;
default:
p_file->m_cur_function = FILEIO_FUNCTION_IDLE;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = -1;
return;
}
// Check if before beginning
if (new_position < 0)
{
new_position = 0;
}
// Check if past EOF
if (new_position > p_file->m_file_size)
{
new_position = p_file->m_file_size;
}
if (p_file->m_host_fd >= 0)
{
// Device ready
p_file->m_cur_position = new_position;
// Do the seek
lseek(p_file->m_host_fd, p_file->m_cur_position, SEEK_SET);
p_file->m_return_value = p_file->m_cur_position;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = p_file->m_cur_position;
}
else
{
// Change position
p_file->m_cur_position = new_position;
// Also set the new current sector
p_file->m_cur_sector = p_file->m_start_sector + (p_file->m_cur_position / SECTOR_SIZE);
p_file->m_return_value = p_file->m_cur_position;
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
s_cur_command_status.m_return_value = p_file->m_cur_position;
}
return;
}
static void FileIO_Set(volatile unsigned int *p_file_handle_index, FileIOVariable variable, int value)
{
SFileIOHandle *p_file;
// See if we have the correct index, and if we can't get it, return
if ((*p_file_handle_index & FILEIO_TEMP_HANDLE_FLAG) && !FileIO_FindFileHandleIndex(p_file_handle_index))
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
p_file = &(gFileHandle[*p_file_handle_index]);
s_cur_command_status.mp_file_handle = p_file;
// Can't change parameters if we're already busy
if (p_file->m_flags & FILEIO_HANDLE_BUSY)
{
s_cur_command_status.m_request_state = REQUEST_OPEN;
return;
}
s_cur_command_status.m_request_state = REQUEST_COMPLETE;
switch (variable)
{
case FILEIO_VAR_PRIORITY:
p_file->m_priority = value;
break;
case FILEIO_VAR_BUFFER_SIZE:
p_file->m_buffer_size = value;
break;
case FILEIO_VAR_STREAM:
p_file->m_stream = value;
break;
case FILEIO_VAR_DESTINATION:
// Not sure how to handle this one yet, since buffers may need to be acquired or freed
if (value == MEM_EE)
{
p_file->m_flags |= FILEIO_HANDLE_EE_MEMORY;
}
else
{
p_file->m_flags &= ~FILEIO_HANDLE_EE_MEMORY;
}
break;
default:
s_cur_command_status.m_return_value = FALSE;
return;
}
s_cur_command_status.m_return_value = TRUE;
return;
}
// EzADPCM_INIT
int AdpcmInit( int pIopBuf )
{
#if 0
int i;
if ( gEECommand & PCMSTATUS_INITIALIZED )
{
return ( 0 );
}
if ( gSem == 0 )
{
struct SemaParam sem;
sem.initCount = 0;
sem.maxCount = 1;
sem.attr = AT_THFIFO;
gSem = CreateSema (&sem);
}
if (gThid == 0)
{
struct ThreadParam param;
param.attr = TH_C;
param.entry = RefreshStreams;
param.initPriority = BASE_priority-3;
param.stackSize = 0x800; // was 800
param.option = 0;
gThid = CreateThread (&param);
printf( "EzADPCM: create thread ID= %d\n", gThid );
StartThread (gThid, (u_long) NULL);
}
memset( gStreamInfo, 0, sizeof( struct StreamInfo ) * NUM_STREAMS );
memset( &gMusicInfo, 0, sizeof( struct StreamInfo ) );
gpIopBuf = pIopBuf;
gEECommand |= PCMSTATUS_INITIALIZED;
//printf( "PCM Irx iop buf %d\n", gpIopBuf );
//Dbug_Printf( "PCM irx is initialized\n" );
#endif
return gThid;
}
// EzADPCM_QUIT
void AdpcmQuit( void )
{
DeleteThread (gThid);
gThid = 0;
#if 0
DeleteSema (gSem);
gSem = 0;
#endif
return;
}
/* internal */
int RefreshStreams( int status )
{
//int i;
while ( 1 )
{
WaitSema(gSem);
#if 0
for ( i = 0; i < NUM_STREAMS; i++ )
{
CheckStream( i );
}
CheckMusic( );
for ( i = 0; i < NUM_STREAMS; i++ )
{
while ( gStreamInfo[ i ].update )
{
gStreamInfo[ i ].update--;
UpdateStream( i );
}
}
while ( gMusicInfo.update )
{
gMusicInfo.update--;
UpdateMusic( );
}
if ( gMusicInfo.volumeSet )
{
gMusicInfo.volumeSet = 0;
AdpcmSetMusicVolumeDirect( gMusicInfo.volume );
}
for ( i = 0; i < NUM_STREAMS; i++ )
{
if ( gStreamInfo[ i ].volumeSet )
{
gStreamInfo[ i ].volumeSet = 0;
AdpcmSetStreamVolumeDirect( gStreamInfo[ i ].volume, i );
}
}
#endif
}
return 0;
}
static ERequestState dispatch(volatile SFileIOTask *p_request_task)
{
volatile SFileIORequestEntry *p_request_entry = &(p_request_task->m_entry);
volatile SFileIORequest *p_request = &(p_request_entry->m_request);
SFileIORequest *p_cont_request = (p_request_task->mp_cont) ? (&p_request_task->mp_cont->m_entry.m_request) : NULL;
// Assume command will need to be completed asynchronously
s_cur_command_status.m_request_state = REQUEST_OPEN;
s_cur_command_status.m_request_id = p_request_entry->m_request_id;
s_cur_command_status.mp_file_handle = NULL;
switch ( p_request->m_command )
{
case FILEIO_INIT:
FileIO_Init(p_request->m_param.m_init.m_priority,
p_request->m_param.m_init.m_buffer_size,
p_request->m_param.m_init.m_memory_dest,
p_request->m_param.m_init.m_init_cd_device);
break;
case FILEIO_OPEN:
if (p_request->m_param.m_open.m_host_read)
{
FileIO_HostOpen((char *) p_request->m_param.m_open.m_file.m_filename,
p_request->m_param.m_open.m_memory_dest,
p_request->m_param.m_open.m_buffer_size,
p_request->m_param.m_open.m_priority,
p_request->m_param.m_open.m_attributes,
p_request->m_param.m_open.m_host_read,
p_cont_request);
} else {
FileIO_Open(p_request->m_param.m_open.m_file.m_raw_name.m_sector_number,
p_request->m_param.m_open.m_file.m_raw_name.m_file_size,
p_request->m_param.m_open.m_memory_dest,
p_request->m_param.m_open.m_buffer_size,
p_request->m_param.m_open.m_priority,
p_request->m_param.m_open.m_attributes);
}
break;
case FILEIO_CLOSE:
FileIO_Close(&p_request->m_param.m_close.m_file_handle);
break;
case FILEIO_READ:
FileIO_Read((SFileIORequest *) p_request, &p_request->m_param.m_rw.m_file_handle, p_request->m_param.m_rw.m_buffer,
p_request->m_param.m_rw.m_size, p_request->m_param.m_rw.m_non_aligned_start_bytes,
p_request->m_param.m_rw.m_non_aligned_end_bytes);
break;
case FILEIO_WRITE:
FileIO_Write((SFileIORequest *) p_request, &p_request->m_param.m_rw.m_file_handle, p_request->m_param.m_rw.m_buffer,
p_request->m_param.m_rw.m_size, p_request->m_param.m_rw.m_non_aligned_start_bytes,
p_request->m_param.m_rw.m_non_aligned_end_bytes);
break;
case FILEIO_SEEK:
FileIO_Seek(&p_request->m_param.m_seek.m_file_handle, p_request->m_param.m_seek.m_offset,
p_request->m_param.m_seek.m_origin);
break;
case FILEIO_SET:
FileIO_Set(&p_request->m_param.m_set.m_file_handle, p_request->m_param.m_set.m_variable,
p_request->m_param.m_set.m_value);
break;
case FILEIO_CONT:
s_cur_command_status.m_request_state = REQUEST_APPEND;
break;
default:
ERROR ("FileIO driver error: unknown command %d \n", p_request->m_command);
s_cur_command_status.m_return_value = -1;
break;
}
// Copy file handle in case we need it later
p_request_task->mp_file_handle = s_cur_command_status.mp_file_handle;
switch (s_cur_command_status.m_request_state)
{
case REQUEST_OPEN:
// This isn't an error or warning anymore: it's now normal
//ERROR (("FileIO driver error: request %d should not end in a open request state\n", p_request_entry->m_request_id));
//printf("FileIO driver warning: request %d with command %d ended in a open request state\n", p_request_entry->m_request_id, p_request->m_command);
break;
case REQUEST_PROCESSING:
break;
case REQUEST_APPEND:
break;
case REQUEST_COMPLETE:
// Send result back to EE now if command completed
SendNowaitResult();
break;
}
return s_cur_command_status.m_request_state;
}
static sceSifCmdData cmdbuffer[FILEIO_NUM_COMMAND_HANDLERS];
#define NUM_FILEIO_REQUESTS (16)
// Note these can be changed in an interrupt
static volatile SFileIORequestEntry sFileIORequestArray[NUM_FILEIO_REQUESTS];
static volatile int sFirstFileIORequest; // Interrupt only reads this value.
static volatile int sFreeFileIORequest; // This is the main variable that changes in the interrupt
// The task entries
static SFileIOTask sFileIOTaskArray[FILEIO_MAX_TASKS];
static SFileIOTask *spTaskFreeList = NULL;
static void request_callback(void *p, void *q);
int fileio_command_loop( void )
{
int oldStat;
int i;
EDeviceType cur_device;
// Create semaphore to signal command came in
struct SemaParam sem;
sem.initCount = 0;
sem.maxCount = 1;
sem.attr = AT_THFIFO;
gCmdSem = CreateSema(&sem);
// Init the stream queue
sFirstFileIORequest = 0;
sFreeFileIORequest = 0;
// Init free task list
spTaskFreeList = NULL;
for (i = 0; i < FILEIO_MAX_TASKS; i++)
{
sFileIOTaskArray[i].mp_file_handle = NULL;
// Add to beginning of list
sFileIOTaskArray[i].mp_next = spTaskFreeList;
spTaskFreeList = &sFileIOTaskArray[i];
}
// Init devices
for (i = 0; i < NUM_DEVICE_TYPES; i++)
{
sFileIODevices[i].m_in_use = FALSE;
sFileIODevices[i].m_waiting_callback = FALSE;
sFileIODevices[i].mp_file_handle = NULL;
sFileIODevices[i].mp_task_list = NULL;
sFileIODevices[i].m_cur_position = -1;
sFileIODevices[i].m_cur_sector = -1;
sFileIODevices[i].mp_buffer[0] = NULL;
sFileIODevices[i].mp_buffer[1] = NULL;
sFileIODevices[i].m_buffer_index = -1;
}
sceSifInitRpc(0);
// set local buffer & functions
CpuSuspendIntr(&oldStat);
// SIFCMD
sceSifSetCmdBuffer( &cmdbuffer[0], FILEIO_NUM_COMMAND_HANDLERS);
sceSifAddCmdHandler(FILEIO_REQUEST_COMMAND, (void *) request_callback, NULL );
CpuResumeIntr(oldStat);
// The loop
while (1) {
//ShowFileIOInfo("waiting for command semaphore\n");
WaitSema(gCmdSem); // Get signal from callback
//ShowFileIOInfo("got command semaphore\n");
// Move new requests into schedule list
// Note that FreeStreamRequest can change in the interrupt at any time
// Also, FirstStreamRequest is examined in the interrupt, but just to make sure we don't overflow the buffer
while (sFreeFileIORequest != sFirstFileIORequest)
{
volatile SFileIORequestEntry *p_request = &(sFileIORequestArray[sFirstFileIORequest]);
SFileIOTask *p_new_task;
ShowFileIOInfo("FileIO: got request id %d with command %x\n", p_request->m_request_id, p_request->m_request.m_command);
// Get a new task entry
p_new_task = spTaskFreeList;
spTaskFreeList = p_new_task->mp_next;
p_new_task->mp_next = NULL;
// Copy data
p_new_task->m_entry = *p_request;
p_new_task->mp_file_handle = NULL;
p_new_task->mp_cont = NULL;
// And put onto unknown device task list
AppendTask(&sFileIODevices[DEVICE_UNKNOWN], p_new_task);
// Increment request index; Note that interrupt can look at this
sFirstFileIORequest = (sFirstFileIORequest + 1) % NUM_FILEIO_REQUESTS;
}
// Process device tasks
for (cur_device = DEVICE_CD; cur_device < NUM_DEVICE_TYPES; cur_device++)
{
SFileIODevice *p_device = &sFileIODevices[cur_device];
SFileIOTask *p_task;
// Skip if busy
if (p_device->m_in_use)
{
continue;
}
p_task = p_device->mp_task_list;
while (p_task)
{
ERequestState ret;
SFileIOTask *p_dispatch_task;
p_dispatch_task = p_task;
ShowFileIOInfo("FileIO: doing request id %d with command %x\n", p_dispatch_task->m_entry.m_request_id, p_dispatch_task->m_entry.m_request.m_command);
ret = dispatch(p_dispatch_task);
p_task = p_task->mp_next;
switch (ret)
{
case REQUEST_OPEN:
// Move to other device
if (p_dispatch_task->mp_file_handle && (p_dispatch_task->mp_file_handle->m_device_type != cur_device))
{
RemoveTask(p_device, p_dispatch_task);
InsertTask(&sFileIODevices[p_dispatch_task->mp_file_handle->m_device_type], p_dispatch_task);
}
break;
case REQUEST_APPEND:
// Add the request to an existing request
if (AppendContRequest(p_dispatch_task))
{
ShowFileIOInfo("***************** FileIO: appended request id %d of command %x\n", p_dispatch_task->m_entry.m_request_id, p_dispatch_task->m_entry.m_request.m_command);
RemoveTask(p_device, p_dispatch_task);
SignalSema(gCmdSem); // So the other task can be retried
}
break;
case REQUEST_PROCESSING:
case REQUEST_COMPLETE:
RemoveTask(p_device, p_dispatch_task);
if (p_dispatch_task->mp_cont) // Check if we have a continuation request
{
p_dispatch_task->mp_cont->mp_next = spTaskFreeList;
spTaskFreeList = p_dispatch_task->mp_cont;
p_dispatch_task->mp_cont = NULL;
}
p_dispatch_task->mp_next = spTaskFreeList;
spTaskFreeList = p_dispatch_task;
break;
}
}
}
}
return 0;
}
static void SendNowaitResult()
{
static SFileIOResultPacket fileIOResult;
static unsigned int last_cmd_id = 0;
static int did_dma_send = FALSE;
// Send the result back
if (did_dma_send && last_cmd_id >= 0) // Wait for previous send to complete (it should already be done, though)
{
while(sceSifDmaStat(last_cmd_id) >= 0)
Kprintf("Waiting for DMA\n");
}
// Gotta copy the id into SStreamRequest
fileIOResult.m_header.opt = s_cur_command_status.m_request_id; // Copy id
fileIOResult.m_return_value = s_cur_command_status.m_return_value;
fileIOResult.m_return_data = s_cur_command_status.m_return_data;
fileIOResult.m_done = TRUE;
fileIOResult.m_non_aligned_data_size = 0;
did_dma_send = TRUE;
last_cmd_id = sceSifSendCmd(FILEIO_RESULT_COMMAND, &fileIOResult, GetResultPacketSize(&fileIOResult), 0, 0, 0);
ShowFileIOInfo("FileIO: sent nowait result id %d back\n", s_cur_command_status.m_request_id);
}
static void request_callback(void *p, void *q)
{
SFileIORequestPacket *h = (SFileIORequestPacket *) p;
// Check to make sure we can add
int nextFreeReq = (sFreeFileIORequest + 1) % NUM_FILEIO_REQUESTS;
if (nextFreeReq == sFirstFileIORequest)
{
// We can't allow a request to be ignored. We must abort
ERROR(("******************************** FileIO driver error: too many requests ********************************\n" ));
}
ShowFileIOInfo("FileIO: received request id %d with command %x\n", h->m_header.opt, h->m_request.m_command);
// Copy the request into the reuest queue
sFileIORequestArray[sFreeFileIORequest].m_request = h->m_request;
sFileIORequestArray[sFreeFileIORequest].m_request_id = h->m_header.opt;
sFreeFileIORequest = nextFreeReq;
// And wake up the dispatch thread
iSignalSema(gCmdSem);
}
// Adds p_task to the end of the device task list
static void AppendTask(SFileIODevice *p_device, SFileIOTask *p_task)
{
SFileIOTask *p_task_list = p_device->mp_task_list;
if (p_task_list)
{
// Find end of list
while (p_task_list->mp_next)
{
p_task_list = p_task_list->mp_next;
}
p_task->mp_next = p_task_list->mp_next;
p_task_list->mp_next = p_task;
}
else
{
// Empty list
p_device->mp_task_list = p_task;
p_task->mp_next = NULL;
}
}
#define GetPriority(x) ((x) ? (x)->m_priority : gDefaultPriority)
// Inserts p_task into the device task list sorted by priority
static void InsertTask(SFileIODevice *p_device, SFileIOTask *p_task)
{
SFileIOTask *p_task_node = p_device->mp_task_list;
SFileIOTask *p_prev_node = NULL;
int priority = GetPriority(p_task->mp_file_handle);
// Find point in list
while (p_task_node)
{
if (priority < GetPriority(p_task_node->mp_file_handle))
{
break;
}
p_prev_node = p_task_node;
p_task_node = p_task_node->mp_next;
}
// Insert
if (p_prev_node)
{
p_task->mp_next = p_task_node;
p_prev_node->mp_next = p_task;
}
else
{
// Head of list
p_task->mp_next = p_device->mp_task_list;
p_device->mp_task_list = p_task;
}
}
// Removes p_task from the device task list
static void RemoveTask(SFileIODevice *p_device, SFileIOTask *p_task)
{
SFileIOTask *p_task_node = p_device->mp_task_list;
if (p_task == p_task_node)
{
// Head of list
p_device->mp_task_list = p_task->mp_next;
}
else
{
// Find item in list
while (p_task_node->mp_next)
{
if (p_task == p_task_node->mp_next)
{
break;
}
p_task_node = p_task_node->mp_next;
}
// Remove
p_task_node->mp_next = p_task->mp_next;
}
p_task->mp_next = NULL;
}
static int AppendContRequest(SFileIOTask *p_task)
{
EDeviceType cur_device;
// Process device tasks
for (cur_device = DEVICE_CD; cur_device < NUM_DEVICE_TYPES; cur_device++)
{
SFileIODevice *p_device = &sFileIODevices[cur_device];
SFileIOTask *p_task_node;
p_task_node = p_device->mp_task_list;
// Find item in list
while (p_task_node)
{
if (p_task->m_entry.m_request_id == p_task_node->m_entry.m_request_id && (p_task != p_task_node))
{
p_task_node->mp_cont = p_task;
return TRUE;
}
p_task_node = p_task_node->mp_next;
}
}
return FALSE;
}
/* ----------------------------------------------------------------
* End on File
* ---------------------------------------------------------------- */