ppsspp/Core/HLE/sceIo.cpp

1339 lines
36 KiB
C++
Raw Normal View History

2012-11-01 15:19:01 +00:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 15:19:01 +00:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#ifdef _WIN32
#include <windows.h>
#endif
#include "../Config.h"
#include "../Host.h"
#include "../SaveState.h"
2012-11-01 15:19:01 +00:00
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "../HW/MemoryStick.h"
#include "Core/CoreTiming.h"
2012-11-01 15:19:01 +00:00
#include "../FileSystems/FileSystem.h"
#include "../FileSystems/MetaFileSystem.h"
#include "../FileSystems/ISOFileSystem.h"
#include "../FileSystems/DirectoryFileSystem.h"
2013-02-24 08:28:40 +00:00
extern "C" {
#include "ext/libkirk/amctrl.h"
};
2012-11-01 15:19:01 +00:00
#include "sceIo.h"
#include "sceRtc.h"
2012-11-01 15:19:01 +00:00
#include "sceKernel.h"
#include "sceKernelMemory.h"
#include "sceKernelThread.h"
// For headless screenshots.
#include "sceDisplay.h"
#define ERROR_ERRNO_FILE_NOT_FOUND 0x80010002
2012-11-01 15:19:01 +00:00
#define ERROR_MEMSTICK_DEVCTL_BAD_PARAMS 0x80220081
#define ERROR_MEMSTICK_DEVCTL_TOO_MANY_CALLBACKS 0x80220082
2013-01-17 08:44:35 +00:00
#define ERROR_KERNEL_BAD_FILE_DESCRIPTOR 0x80020323
#define PSP_DEV_TYPE_ALIAS 0x20
2012-11-01 15:19:01 +00:00
/*
TODO: async io is missing features!
flash0: - fat access - system file volume
flash1: - fat access - configuration file volume
flashfat#: this too
lflash: - block access - entire flash
fatms: memstick
isofs: fat access - umd
disc0: fat access - umd
ms0: - fat access - memcard
umd: - block access - umd
irda?: - (?=0..9) block access - infra-red port (doesnt support seeking, maybe send/recieve data from port tho)
mscm0: - block access - memstick cm??
umd00: block access - umd
umd01: block access - umd
2012-11-01 15:19:01 +00:00
*/
#define O_RDONLY 0x0001
#define O_WRONLY 0x0002
#define O_RDWR 0x0003
#define O_NBLOCK 0x0010
#define O_APPEND 0x0100
2013-01-17 08:44:35 +00:00
#define O_CREAT 0x0200
#define O_TRUNC 0x0400
2012-11-01 15:19:01 +00:00
#define O_NOWAIT 0x8000
2013-02-24 08:28:40 +00:00
#define O_NPDRM 0x40000000
2012-11-01 15:19:01 +00:00
typedef s32 SceMode;
typedef s64 SceOff;
typedef u64 SceIores;
typedef u32 (*DeferredAction)(SceUID id, int param);
DeferredAction defAction = 0;
u32 defParam = 0;
int asyncNotifyEvent = -1;
2012-11-01 15:19:01 +00:00
#define SCE_STM_FDIR 0x1000
#define SCE_STM_FREG 0x2000
#define SCE_STM_FLNK 0x4000
2013-01-17 08:44:35 +00:00
enum {
TYPE_DIR=0x10,
TYPE_FILE=0x20
2012-11-01 15:19:01 +00:00
};
#ifdef __SYMBIAN32__
#undef st_ctime
#undef st_atime
#undef st_mtime
#endif
struct SceIoStat {
2012-11-01 15:19:01 +00:00
SceMode st_mode;
unsigned int st_attr;
SceOff st_size;
ScePspDateTime st_ctime;
ScePspDateTime st_atime;
ScePspDateTime st_mtime;
unsigned int st_private[6];
};
struct SceIoDirEnt {
2012-11-01 15:19:01 +00:00
SceIoStat d_stat;
char d_name[256];
u32 d_private;
};
#ifndef __SYMBIAN32__
struct dirent {
u32 unk0;
u32 type;
u32 size;
u32 unk[19];
char name[0x108];
2012-11-01 15:19:01 +00:00
};
#endif
2012-11-01 15:19:01 +00:00
2013-01-02 11:35:37 +00:00
class FileNode : public KernelObject {
public:
FileNode() : callbackID(0), callbackArg(0), asyncResult(0), pendingAsyncResult(false), sectorBlockMode(false), closePending(false), npdrm(0), pgdInfo(NULL) {}
2013-01-02 11:35:37 +00:00
~FileNode() {
pspFileSystem.CloseFile(handle);
}
const char *GetName() {return fullpath.c_str();}
const char *GetTypeName() {return "OpenFile";}
void GetQuickInfo(char *ptr, int size) {
sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle));
}
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; }
int GetIDType() const { return PPSSPP_KERNEL_TMID_File; }
virtual void DoState(PointerWrap &p) {
p.Do(fullpath);
p.Do(handle);
p.Do(callbackID);
p.Do(callbackArg);
p.Do(asyncResult);
p.Do(pendingAsyncResult);
p.Do(sectorBlockMode);
p.Do(closePending);
p.Do(info);
p.Do(openMode);
// TODO: Savestate PGD files?
2013-01-02 11:35:37 +00:00
p.DoMarker("File");
}
std::string fullpath;
u32 handle;
u32 callbackID;
u32 callbackArg;
s64 asyncResult;
2013-01-02 11:35:37 +00:00
bool pendingAsyncResult;
bool sectorBlockMode;
2013-01-17 08:44:35 +00:00
bool closePending;
PSPFileInfo info;
u32 openMode;
2013-02-24 08:28:40 +00:00
u32 npdrm;
PGD_DESC *pgdInfo;
2013-01-02 11:35:37 +00:00
};
2013-02-24 08:28:40 +00:00
/******************************************************************************/
/******************************************************************************/
void __IoCompleteAsyncIO(SceUID id);
2013-01-11 00:25:30 +00:00
static void TellFsThreadEnded (SceUID threadID) {
2013-01-10 11:27:10 +00:00
pspFileSystem.ThreadEnded(threadID);
}
// Async IO seems to work roughly like this:
// 1. Game calls SceIo*Async() to start the process.
// 2. This runs a thread with a customizable priority.
// 3. The operation runs, which takes an inconsistent amount of time from UMD.
// 4. Once done (regardless of other syscalls), the fd-registered callback is notified.
// 5. The game can find out via *CB() or sceKernelCheckCallback().
// 6. At this point, the fd is STILL not usable.
// 7. One must call sceIoWaitAsync / sceIoWaitAsyncCB / sceIoPollAsync / possibly sceIoGetAsyncStat.
// 8. Finally, the fd is usable (or closed via sceIoCloseAsync.) Presumably the io thread has joined now.
// TODO: We don't do any of that yet.
// For now, let's at least delay the callback mnotification.
void __IoAsyncNotify(u64 userdata, int cyclesLate) {
__IoCompleteAsyncIO((SceUID) userdata);
}
void __IoInit() {
2012-11-01 15:19:01 +00:00
INFO_LOG(HLE, "Starting up I/O...");
MemoryStick_SetFatState(PSP_FAT_MEMORYSTICK_STATE_ASSIGNED);
asyncNotifyEvent = CoreTiming::RegisterEvent("IoAsyncNotify", __IoAsyncNotify);
2012-11-01 15:19:01 +00:00
#ifdef _WIN32
char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT];
char memstickpath[_MAX_PATH];
char flash0path[_MAX_PATH];
2012-11-01 15:19:01 +00:00
GetModuleFileName(NULL,path_buffer,sizeof(path_buffer));
char *winpos = strstr(path_buffer, "Windows");
if (winpos)
*winpos = 0;
2012-11-01 15:19:01 +00:00
strcat(path_buffer, "dummy.txt");
_splitpath_s(path_buffer, drive, dir, file, ext );
// Mount a couple of filesystems
sprintf(memstickpath, "%s%smemstick\\", drive, dir);
sprintf(flash0path, "%s%sflash0\\", drive, dir);
2012-11-01 15:19:01 +00:00
#else
// TODO
std::string memstickpath = g_Config.memCardDirectory;
std::string flash0path = g_Config.flashDirectory;
2012-11-01 15:19:01 +00:00
#endif
DirectoryFileSystem *memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath);
#ifdef ANDROID
VFSFileSystem *flash0 = new VFSFileSystem(&pspFileSystem, "flash0");
#else
DirectoryFileSystem *flash0 = new DirectoryFileSystem(&pspFileSystem, flash0path);
#endif
pspFileSystem.Mount("ms0:", memstick);
pspFileSystem.Mount("fatms0:", memstick);
pspFileSystem.Mount("fatms:", memstick);
pspFileSystem.Mount("flash0:", flash0);
2013-01-17 08:44:35 +00:00
2013-01-10 11:27:10 +00:00
__KernelListenThreadEnd(&TellFsThreadEnded);
2012-11-01 15:19:01 +00:00
}
void __IoDoState(PointerWrap &p) {
// TODO: defAction is hard to save, and not the right way anyway.
// Should probbly be an enum and on the FileNode anyway.
if (defAction != NULL) {
WARN_LOG(HLE, "FIXME: Savestate failure: deferred IO not saved yet.");
}
p.Do(asyncNotifyEvent);
CoreTiming::RestoreRegisterEvent(asyncNotifyEvent, "IoAsyncNotify", __IoAsyncNotify);
}
void __IoShutdown() {
defAction = 0;
defParam = 0;
2012-11-01 15:19:01 +00:00
}
2013-01-02 11:35:37 +00:00
u32 __IoGetFileHandleFromId(u32 id, u32 &outError)
{
FileNode *f = kernelObjects.Get < FileNode > (id, outError);
if (!f) {
return -1;
}
return f->handle;
}
2013-01-17 08:44:35 +00:00
u32 sceIoAssign(u32 alias_addr, u32 physical_addr, u32 filesystem_addr, int mode, u32 arg_addr, int argSize)
{
std::string alias = Memory::GetCharPointer(alias_addr);
std::string physical_dev = Memory::GetCharPointer(physical_addr);
std::string filesystem_dev = Memory::GetCharPointer(filesystem_addr);
std::string perm;
switch (mode) {
case 0:
perm = "IOASSIGN_RDWR";
break;
case 1:
perm = "IOASSIGN_RDONLY";
break;
default:
perm = "unhandled";
2013-01-17 08:44:35 +00:00
break;
}
DEBUG_LOG(HLE, "sceIoAssign(%s, %s, %s, %s, %08x, %i)", alias.c_str(), physical_dev.c_str(), filesystem_dev.c_str(), perm.c_str(), arg_addr, argSize);
return 0;
}
u32 sceIoUnassign(const char *alias)
{
DEBUG_LOG(HLE, "sceIoUnassign(%s)", alias);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 sceKernelStdin() {
DEBUG_LOG(HLE, "3=sceKernelStdin()");
return 3;
2012-11-01 15:19:01 +00:00
}
u32 sceKernelStdout() {
DEBUG_LOG(HLE, "1=sceKernelStdout()");
return 1;
2012-11-01 15:19:01 +00:00
}
u32 sceKernelStderr() {
DEBUG_LOG(HLE, "2=sceKernelStderr()");
return 2;
2012-11-01 15:19:01 +00:00
}
void __IoCompleteAsyncIO(SceUID id) {
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
if (f->callbackID) {
__KernelNotifyCallback(THREAD_CALLBACK_IO, f->callbackID, f->callbackArg);
2012-11-01 15:19:01 +00:00
}
}
}
void __IoCopyDate(ScePspDateTime& date_out, const tm& date_in)
{
date_out.year = date_in.tm_year+1900;
date_out.month = date_in.tm_mon+1;
date_out.day = date_in.tm_mday;
date_out.hour = date_in.tm_hour;
date_out.minute = date_in.tm_min;
date_out.second = date_in.tm_sec;
date_out.microsecond = 0;
}
void __IoGetStat(SceIoStat *stat, PSPFileInfo &info) {
2012-11-01 15:19:01 +00:00
memset(stat, 0xfe, sizeof(SceIoStat));
stat->st_size = (s64) info.size;
2012-11-01 15:19:01 +00:00
int type, attr;
if (info.type & FILETYPE_DIRECTORY)
type = SCE_STM_FDIR, attr = TYPE_DIR;
else
type = SCE_STM_FREG, attr = TYPE_FILE;
stat->st_mode = type | info.access;
2012-11-01 15:19:01 +00:00
stat->st_attr = attr;
stat->st_size = info.size;
__IoCopyDate(stat->st_atime, info.atime);
__IoCopyDate(stat->st_ctime, info.ctime);
__IoCopyDate(stat->st_mtime, info.mtime);
2012-11-01 15:19:01 +00:00
stat->st_private[0] = info.startSector;
}
u32 sceIoGetstat(const char *filename, u32 addr) {
2012-11-27 09:18:36 +00:00
SceIoStat stat;
2012-11-01 15:19:01 +00:00
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
if (info.exists) {
__IoGetStat(&stat, info);
if (Memory::IsValidAddress(addr)) {
Memory::WriteStruct(addr, &stat);
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "sceIoGetstat(%s, %08x) : sector = %08x", filename, addr, info.startSector);
return 0;
} else {
ERROR_LOG(HLE, "sceIoGetstat(%s, %08x) : bad address", filename, addr);
return -1;
}
} else {
DEBUG_LOG(HLE, "sceIoGetstat(%s, %08x) : FILE NOT FOUND", filename, addr);
return ERROR_ERRNO_FILE_NOT_FOUND;
}
2012-11-01 15:19:01 +00:00
}
2013-02-24 08:28:40 +00:00
u32 npdrmRead(FileNode *f, u8 *data, int size) {
PGD_DESC *pgd = f->pgdInfo;
u32 block, offset;
u32 remain_size, copy_size;
block = pgd->file_offset/pgd->block_size;
offset = pgd->file_offset%pgd->block_size;
remain_size = size;
while(remain_size){
if(pgd->current_block!=block){
pspFileSystem.ReadFile(f->handle, pgd->block_buf, pgd->block_size);
pgd_decrypt_block(pgd, block);
pgd->current_block = block;
}
if(offset+remain_size>pgd->block_size){
copy_size = pgd->block_size-offset;
block += 1;
offset = 0;
}else{
copy_size = remain_size;
}
memcpy(data, pgd->block_buf+offset, copy_size);
data += copy_size;
remain_size -= copy_size;
pgd->file_offset += copy_size;
}
return size;
}
2012-12-05 14:49:48 +00:00
//Not sure about wrapping it or not, since the log seems to take the address of the data var
u32 sceIoRead(int id, u32 data_addr, int size) {
if (id == 3) {
DEBUG_LOG(HLE, "sceIoRead STDIN");
return 0; //stdin
2012-11-01 15:19:01 +00:00
}
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
if(!(f->openMode & FILEACCESS_READ))
{
return ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
}
else if (Memory::IsValidAddress(data_addr)) {
u8 *data = (u8*) Memory::GetPointer(data_addr);
2013-02-24 08:28:40 +00:00
if(f->npdrm){
f->asyncResult = npdrmRead(f, data, size);
2013-02-24 08:28:40 +00:00
}else{
f->asyncResult = pspFileSystem.ReadFile(f->handle, data, size);
2013-02-24 08:28:40 +00:00
}
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "%i=sceIoRead(%d, %08x , %i)", f->asyncResult, id, data_addr, size);
return (u32) f->asyncResult;
} else {
ERROR_LOG(HLE, "sceIoRead Reading into bad pointer %08x", data_addr);
return -1;
2012-11-01 15:19:01 +00:00
}
} else {
ERROR_LOG(HLE, "sceIoRead ERROR: no file open");
return error;
2012-11-01 15:19:01 +00:00
}
}
2013-01-17 08:44:35 +00:00
u32 sceIoWrite(int id, void *data_ptr, int size)
2012-11-01 15:19:01 +00:00
{
if (id == 2) {
//stderr!
const char *str = (const char*) data_ptr;
INFO_LOG(HLE, "stderr: %s", str);
return size;
} else if (id == 1) {
2012-11-01 15:19:01 +00:00
//stdout!
char *str = (char *) data_ptr;
2012-11-01 15:19:01 +00:00
char temp = str[size];
str[size] = 0;
INFO_LOG(HLE, "stdout: %s", str);
str[size] = temp;
return size;
2012-11-01 15:19:01 +00:00
}
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
if(!(f->openMode & FILEACCESS_WRITE))
{
return ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
}
else
{
u8 *data = (u8*) data_ptr;
f->asyncResult = pspFileSystem.WriteFile(f->handle, data, size);
return (u32) f->asyncResult;
}
} else {
ERROR_LOG(HLE, "sceIoWrite ERROR: no file open");
return error;
2012-11-01 15:19:01 +00:00
}
}
2013-01-17 08:44:35 +00:00
u32 sceIoWriteAsync(int id, void *data_ptr, int size)
{
DEBUG_LOG(HLE, "sceIoWriteAsync(%d)", id);
sceIoWrite(id, data_ptr, size);
__IoCompleteAsyncIO(id);
return 0;
}
u32 sceIoGetDevType(int id)
{
ERROR_LOG(HLE, "UNIMPL sceIoGetDevType(%d)", id);
2013-01-17 08:44:35 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
int result;
if (f)
result = PSP_DEV_TYPE_ALIAS;
else {
ERROR_LOG(HLE, "sceIoGetDevType: unknown id %d", id);
2013-01-17 08:44:35 +00:00
result = ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
}
return result;
}
u32 sceIoCancel(int id)
{
ERROR_LOG(HLE, "UNIMPL sceIoCancel(%d)", id);
2013-01-17 08:44:35 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
2013-01-17 08:44:35 +00:00
f->closePending = true;
} else {
ERROR_LOG(HLE, "sceIoCancel: unknown id %d", id);
error = ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
2013-01-17 08:44:35 +00:00
}
return error;
2013-01-17 08:44:35 +00:00
}
2013-02-24 08:28:40 +00:00
u32 npdrmLseek(FileNode *f, s32 where, FileMove whence)
{
u32 newPos;
if(whence==FILEMOVE_BEGIN){
newPos = where;
}else if(whence==FILEMOVE_CURRENT){
newPos = f->pgdInfo->file_offset+where;
}else{
newPos = f->pgdInfo->data_size+where;
}
if(newPos<0 || newPos>f->pgdInfo->data_size){
return -EINVAL;
}
f->pgdInfo->file_offset = newPos;
return newPos;
}
s64 sceIoLseek(int id, s64 offset, int whence) {
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
2012-11-01 15:19:01 +00:00
FileMove seek = FILEMOVE_BEGIN;
bool outOfBound = false;
2013-01-22 01:51:36 +00:00
s64 newPos = 0;
switch (whence) {
case 0:
newPos = offset;
break;
case 1:
newPos = pspFileSystem.GetSeekPos(f->handle) + offset;
seek = FILEMOVE_CURRENT;
break;
case 2:
newPos = f->info.size + offset;
seek = FILEMOVE_END;
break;
2012-11-01 15:19:01 +00:00
}
if(newPos < 0)
return -1;
2012-11-01 15:19:01 +00:00
2013-02-24 08:28:40 +00:00
if(f->npdrm){
f->asyncResult = npdrmLseek(f, (s32)offset, seek);
}else{
f->asyncResult = pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
2013-02-24 08:28:40 +00:00
}
DEBUG_LOG(HLE, "%i = sceIoLseek(%d,%i,%i)", (u32) f->asyncResult, id, (int) offset, whence);
return (u32) f->asyncResult;
} else {
2013-01-17 08:44:35 +00:00
ERROR_LOG(HLE, "sceIoLseek(%d, %i, %i) - ERROR: invalid file", id, (int) offset, whence);
return error;
2012-11-01 15:19:01 +00:00
}
}
u32 sceIoLseek32(int id, int offset, int whence) {
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
FileMove seek = FILEMOVE_BEGIN;
bool outOfBound = false;
2013-01-22 01:51:36 +00:00
s64 newPos = 0;
switch (whence) {
case 0:
newPos = offset;
break;
case 1:
newPos = pspFileSystem.GetSeekPos(f->handle) + offset;
seek = FILEMOVE_CURRENT;
break;
case 2:
newPos = f->info.size + offset;
seek = FILEMOVE_END;
break;
2012-11-01 15:19:01 +00:00
}
if(newPos < 0)
return -1;
2012-11-01 15:19:01 +00:00
2013-02-24 08:28:40 +00:00
if(f->npdrm){
f->asyncResult = npdrmLseek(f, (s32)offset, seek);
}else{
f->asyncResult = pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
2013-02-24 08:28:40 +00:00
}
DEBUG_LOG(HLE, "%i = sceIoLseek32(%d,%i,%i)", (u32) f->asyncResult, id, (int) offset, whence);
return (u32) f->asyncResult;
} else {
2013-01-22 01:51:36 +00:00
ERROR_LOG(HLE, "sceIoLseek32(%d, %i, %i) - ERROR: invalid file", id, (int) offset, whence);
return error;
2012-11-01 15:19:01 +00:00
}
}
u32 sceIoOpen(const char* filename, int flags, int mode) {
2012-11-01 15:19:01 +00:00
//memory stick filename
int access = FILEACCESS_NONE;
if (flags & O_RDONLY)
access |= FILEACCESS_READ;
if (flags & O_WRONLY)
access |= FILEACCESS_WRITE;
if (flags & O_APPEND)
access |= FILEACCESS_APPEND;
if (flags & O_CREAT)
access |= FILEACCESS_CREATE;
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
u32 h = pspFileSystem.OpenFile(filename, (FileAccess) access);
2012-11-01 15:19:01 +00:00
if (h == 0)
{
ERROR_LOG(HLE,
2013-01-17 08:44:35 +00:00
"ERROR_ERRNO_FILE_NOT_FOUND=sceIoOpen(%s, %08x, %08x) - file not found", filename, flags, mode);
return ERROR_ERRNO_FILE_NOT_FOUND;
2012-11-01 15:19:01 +00:00
}
FileNode *f = new FileNode();
SceUID id = kernelObjects.Create(f);
f->handle = h;
f->fullpath = filename;
f->asyncResult = id;
f->info = info;
f->openMode = access;
2013-02-24 08:28:40 +00:00
f->npdrm = (flags & O_NPDRM)? true: false;
DEBUG_LOG(HLE, "%i=sceIoOpen(%s, %08x, %08x)", id, filename, flags, mode);
return id;
2012-11-01 15:19:01 +00:00
}
u32 sceIoClose(int id) {
2013-02-24 08:28:40 +00:00
u32 error;
DEBUG_LOG(HLE, "sceIoClose(%d)", id);
2013-02-24 08:28:40 +00:00
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if(f && f->npdrm){
2013-02-24 12:19:54 +00:00
pgd_close(f->pgdInfo);
2013-02-24 08:28:40 +00:00
}
return kernelObjects.Destroy < FileNode > (id);
2012-11-01 15:19:01 +00:00
}
u32 sceIoRemove(const char *filename) {
DEBUG_LOG(HLE, "sceIoRemove(%s)", filename);
if(!pspFileSystem.GetFileInfo(filename).exists)
return ERROR_ERRNO_FILE_NOT_FOUND;
pspFileSystem.RemoveFile(filename);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 sceIoMkdir(const char *dirname, int mode) {
DEBUG_LOG(HLE, "sceIoMkdir(%s, %i)", dirname, mode);
if (pspFileSystem.MkDir(dirname))
return 0;
2012-11-01 15:19:01 +00:00
else
return -1;
2012-11-01 15:19:01 +00:00
}
u32 sceIoRmdir(const char *dirname) {
DEBUG_LOG(HLE, "sceIoRmdir(%s)", dirname);
if (pspFileSystem.RmDir(dirname))
return 0;
2012-11-01 15:19:01 +00:00
else
return -1;
2012-11-01 15:19:01 +00:00
}
2013-01-17 08:44:35 +00:00
u32 sceIoSync(const char *devicename, int flag) {
DEBUG_LOG(HLE, "UNIMPL sceIoSync(%s, %i)", devicename, flag);
return 0;
2012-11-01 15:19:01 +00:00
}
struct DeviceSize {
u32 maxClusters;
u32 freeClusters;
2012-11-01 15:19:01 +00:00
u32 maxSectors;
u32 sectorSize;
u32 sectorCount;
2012-11-01 15:19:01 +00:00
};
u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, int outLen) {
if (strcmp(name, "emulator:")) {
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen);
}
// UMD checks
switch (cmd) {
case 0x01F20001: // Get Disc Type.
if (Memory::IsValidAddress(outPtr)) {
Memory::Write_U32(0x10, outPtr); // Game disc
return 0;
} else {
return -1;
}
break;
case 0x01F20002: // Get current LBA.
if (Memory::IsValidAddress(outPtr)) {
Memory::Write_U32(0, outPtr); // Game disc
return 0;
} else {
return -1;
}
break;
case 0x01F100A3: // Seek
return 0;
}
// This should really send it on to a FileSystem implementation instead.
if (!strcmp(name, "mscmhc0:") || !strcmp(name, "ms0:"))
{
switch (cmd)
{
// does one of these set a callback as well? (see coded arms)
case 0x02015804: // Register callback
if (Memory::IsValidAddress(argAddr) && argLen == 4) {
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) {
DEBUG_LOG(HLE, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId);
__KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State());
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
}
break;
case 0x02025805: // Unregister callback
if (Memory::IsValidAddress(argAddr) && argLen == 4) {
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) {
DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick callback %i", cbId);
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
}
break;
case 0x02025801: // Memstick Driver status?
if (Memory::IsValidAddress(outPtr) && outLen >= 4) {
Memory::Write_U32(4, outPtr); // JPSCP: The right return value is 4 for some reason
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
case 0x02025806: // Memory stick inserted?
if (Memory::IsValidAddress(outPtr) && outLen >= 4) {
Memory::Write_U32(1, outPtr);
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
case 0x02425818: // Get memstick size etc
// Pretend we have a 2GB memory stick.
if (Memory::IsValidAddress(argAddr) && argLen >= 4) { // "Should" be outPtr but isn't
u32 pointer = Memory::Read_U32(argAddr);
u32 sectorSize = 0x200;
u32 memStickSectorSize = 32 * 1024;
u32 sectorCount = memStickSectorSize / sectorSize;
u64 freeSize = 1 * 1024 * 1024 * 1024;
DeviceSize deviceSize;
2012-12-21 09:18:52 +00:00
deviceSize.maxClusters = (u32)((freeSize * 95 / 100) / (sectorSize * sectorCount));
deviceSize.freeClusters = deviceSize.maxClusters;
deviceSize.maxSectors = deviceSize.maxClusters;
deviceSize.sectorSize = sectorSize;
deviceSize.sectorCount = sectorCount;
Memory::WriteStruct(pointer, &deviceSize);
DEBUG_LOG(HLE, "Returned memstick size: maxSectors=%i", deviceSize.maxSectors);
return 0;
} else {
ERROR_LOG(HLE, "memstick size query: bad params");
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
}
}
if (!strcmp(name, "fatms0:"))
{
switch (cmd) {
case 0x02415821: // MScmRegisterMSInsertEjectCallback
{
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) {
DEBUG_LOG(HLE, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId);
__KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState());
return 0;
} else {
return -1;
}
}
break;
case 0x02415822: // MScmUnregisterMSInsertEjectCallback
{
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) {
DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId);
return 0;
} else {
return -1;
}
}
case 0x02415823: // Set FAT as enabled
if (Memory::IsValidAddress(argAddr) && argLen == 4) {
MemoryStick_SetFatState((MemStickFatState)Memory::Read_U32(argAddr));
return 0;
} else {
ERROR_LOG(HLE, "Failed 0x02415823 fat");
return -1;
}
break;
case 0x02425823: // Check if FAT enabled
if (Memory::IsValidAddress(outPtr) && outLen == 4) {
Memory::Write_U32(MemoryStick_FatState(), outPtr);
return 0;
} else {
ERROR_LOG(HLE, "Failed 0x02425823 fat");
return -1;
}
break;
case 0x02425818: // Get memstick size etc
// Pretend we have a 2GB memory stick.
{
if (Memory::IsValidAddress(argAddr) && argLen >= 4) { // NOTE: not outPtr
u32 pointer = Memory::Read_U32(argAddr);
u32 sectorSize = 0x200;
u32 memStickSectorSize = 32 * 1024;
u32 sectorCount = memStickSectorSize / sectorSize;
u64 freeSize = 1 * 1024 * 1024 * 1024;
DeviceSize deviceSize;
2012-12-21 09:18:52 +00:00
deviceSize.maxClusters = (u32)((freeSize * 95 / 100) / (sectorSize * sectorCount));
deviceSize.freeClusters = deviceSize.maxClusters;
deviceSize.maxSectors = deviceSize.maxClusters;
deviceSize.sectorSize = sectorSize;
deviceSize.sectorCount = sectorCount;
Memory::WriteStruct(pointer, &deviceSize);
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
}
}
}
if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:"))
{
// Emulator special tricks!
switch (cmd)
{
case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY
if (Memory::IsValidAddress(outPtr))
Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests!
return 0;
case 2: // EMULATOR_DEVCTL__SEND_OUTPUT
{
std::string data(Memory::GetCharPointer(argAddr), argLen);
2013-03-06 23:27:00 +00:00
if (PSP_CoreParameter().printfEmuLog) {
host->SendDebugOutput(data.c_str());
2013-03-06 23:27:00 +00:00
} else {
if (PSP_CoreParameter().collectEmuLog) {
*PSP_CoreParameter().collectEmuLog += data;
2013-03-06 23:45:34 +00:00
} else {
2013-03-06 23:27:00 +00:00
DEBUG_LOG(HLE, "%s", data.c_str());
}
}
return 0;
}
case 3: // EMULATOR_DEVCTL__IS_EMULATOR
if (Memory::IsValidAddress(outPtr))
Memory::Write_U32(1, outPtr);
return 0;
case 4: // EMULATOR_DEVCTL__VERIFY_STATE
// Note that this is async, and makes sure the save state matches up.
SaveState::Verify();
// TODO: Maybe save/load to a file just to be sure?
return 0;
case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT
u8 *topaddr;
u32 linesize, pixelFormat;
__DisplayGetFramebuf(&topaddr, &linesize, &pixelFormat, 0);
// TODO: Convert based on pixel format / mode / something?
host->SendDebugScreenshot(topaddr, linesize, 272);
return 0;
}
ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS");
return 0;
}
//089c6d1c weird branch
/*
089c6bdc ]: HLE: sceKernelCreateCallback(name= MemoryStick Detection ,entry= 089c7484 ) (z_un_089c6bc4)
089c6c18 ]: HLE: sceIoDevctl("mscmhc0:", 02015804, 09ffb9c0, 4, 00000000, 0) (z_un_089c6bc4)
089c6c40 ]: HLE: sceKernelCreateCallback(name= MemoryStick Assignment ,entry= 089c7534 ) (z_un_089c6bc4)
089c6c78 ]: HLE: sceIoDevctl("fatms0:", 02415821, 09ffb9c4, 4, 00000000, 0) (z_un_089c6bc4)
089c6cac ]: HLE: sceIoDevctl("mscmhc0:", 02025806, 00000000, 0, 09ffb9c8, 4) (z_un_089c6bc4)
*/
return SCE_KERNEL_ERROR_UNSUP;
}
u32 sceIoRename(const char *from, const char *to) {
DEBUG_LOG(HLE, "sceIoRename(%s, %s)", from, to);
if(!pspFileSystem.GetFileInfo(from).exists)
return ERROR_ERRNO_FILE_NOT_FOUND;
if(!pspFileSystem.RenameFile(from, to))
WARN_LOG(HLE, "Could not move %s to %s\n",from, to);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 sceIoChdir(const char *dirname) {
DEBUG_LOG(HLE, "sceIoChdir(%s)", dirname);
pspFileSystem.ChDir(dirname);
return 0;
2012-11-01 15:19:01 +00:00
}
int sceIoChangeAsyncPriority(int id, int priority)
2012-11-01 15:19:01 +00:00
{
ERROR_LOG(HLE, "UNIMPL sceIoChangeAsyncPriority(%d, %d)", id, priority);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 __IoClose(SceUID actedFd, int closedFd)
{
DEBUG_LOG(HLE, "Deferred IoClose(%d, %d)", actedFd, closedFd);
__IoCompleteAsyncIO(closedFd);
return kernelObjects.Destroy < FileNode > (closedFd);
}
2013-01-17 08:44:35 +00:00
int sceIoCloseAsync(int id)
2012-11-01 15:19:01 +00:00
{
DEBUG_LOG(HLE, "sceIoCloseAsync(%d)", id);
//sceIoClose();
// TODO: Not sure this is a good solution. Seems like you can defer one per fd.
defAction = &__IoClose;
defParam = id;
return 0;
2012-11-01 15:19:01 +00:00
}
2012-12-05 14:49:48 +00:00
u32 sceIoLseekAsync(int id, s64 offset, int whence)
2012-11-01 15:19:01 +00:00
{
DEBUG_LOG(HLE, "sceIoLseekAsync(%d) sorta implemented", id);
sceIoLseek(id, offset, whence);
__IoCompleteAsyncIO(id);
return 0;
2012-11-01 15:19:01 +00:00
}
2012-12-05 14:49:48 +00:00
u32 sceIoSetAsyncCallback(int id, u32 clbckId, u32 clbckArg)
2012-11-01 15:19:01 +00:00
{
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "sceIoSetAsyncCallback(%d, %i, %08x)", id, clbckId, clbckArg);
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
2012-11-01 15:19:01 +00:00
if (f)
{
// TODO: Check replacing / updating?
f->callbackID = clbckId;
f->callbackArg = clbckArg;
return 0;
2012-11-01 15:19:01 +00:00
}
else
{
return error;
2012-11-01 15:19:01 +00:00
}
}
2012-12-05 14:49:48 +00:00
u32 sceIoLseek32Async(int id, int offset, int whence)
2012-11-01 15:19:01 +00:00
{
DEBUG_LOG(HLE, "sceIoLseek32Async(%d) sorta implemented", id);
sceIoLseek32(id, offset, whence);
__IoCompleteAsyncIO(id);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 sceIoOpenAsync(const char *filename, int flags, int mode)
2012-11-01 15:19:01 +00:00
{
DEBUG_LOG(HLE, "sceIoOpenAsync() sorta implemented");
u32 fd = sceIoOpen(filename, flags, mode);
// We have to return an fd here, which may have been destroyed when we reach Wait if it failed.
if (fd == ERROR_ERRNO_FILE_NOT_FOUND)
{
// TODO: Should close/delete after waitasync/etc.
FileNode *f = new FileNode();
fd = kernelObjects.Create(f);
f->handle = fd;
f->fullpath = filename;
f->asyncResult = (s32) ERROR_ERRNO_FILE_NOT_FOUND;
}
// TODO: Timing is very inconsistent. From ms0, 10ms - 20ms depending on filesize/dir depth? From umd, can take > 1s.
// For now let's aim low.
CoreTiming::ScheduleEvent(usToCycles(100), asyncNotifyEvent, fd);
return fd;
}
2012-11-01 15:19:01 +00:00
2012-12-05 14:49:48 +00:00
u32 sceIoReadAsync(int id, u32 data_addr, int size)
2012-11-01 15:19:01 +00:00
{
DEBUG_LOG(HLE, "sceIoReadAsync(%d)", id);
sceIoRead(id, data_addr, size);
__IoCompleteAsyncIO(id);
return 0;
2012-11-01 15:19:01 +00:00
}
u32 sceIoGetAsyncStat(int id, u32 poll, u32 address)
2012-11-01 15:19:01 +00:00
{
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
2012-11-01 15:19:01 +00:00
if (f)
{
Memory::Write_U64((u64) f->asyncResult, address);
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x) (HACK)", f->asyncResult, id, poll, address);
2012-12-26 07:02:53 +00:00
if (!poll)
hleReSchedule("io waited");
return 0; //completed
2012-11-01 15:19:01 +00:00
}
else
{
ERROR_LOG(HLE, "ERROR - sceIoGetAsyncStat with invalid id %i", id);
return -1;
2012-11-01 15:19:01 +00:00
}
}
2012-12-26 07:02:53 +00:00
int sceIoWaitAsync(int id, u32 address) {
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
2012-11-27 09:18:36 +00:00
u64 res = f->asyncResult;
if (defAction) {
2012-11-27 09:18:36 +00:00
res = defAction(id, defParam);
2012-11-01 15:19:01 +00:00
defAction = 0;
}
Memory::Write_U64(res, address);
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "%i = sceIoWaitAsync(%i, %08x) (HACK)", (u32) res, id, address);
2012-12-26 07:02:53 +00:00
hleReSchedule("io waited");
return 0; //completed
} else {
ERROR_LOG(HLE, "ERROR - sceIoWaitAsync waiting for invalid id %i", id);
2012-12-26 07:02:53 +00:00
return -1;
2012-11-01 15:19:01 +00:00
}
}
2012-12-26 07:02:53 +00:00
int sceIoWaitAsyncCB(int id, u32 address) {
2012-11-01 15:19:01 +00:00
// Should process callbacks here
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
2012-11-27 09:18:36 +00:00
u64 res = f->asyncResult;
if (defAction) {
2012-11-27 09:18:36 +00:00
res = defAction(id, defParam);
2012-11-01 15:19:01 +00:00
defAction = 0;
}
Memory::Write_U64(res, address);
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "%i = sceIoWaitAsyncCB(%i, %08x) (HACK)", (u32) res, id, address);
2012-12-26 07:02:53 +00:00
hleCheckCurrentCallbacks();
hleReSchedule(true, "io waited");
return 0; //completed
} else {
2013-01-17 08:44:35 +00:00
ERROR_LOG(HLE, "ERROR - sceIoWaitAsyncCB waiting for invalid id %i", id);
2012-12-26 07:02:53 +00:00
return -1;
2012-11-01 15:19:01 +00:00
}
}
u32 sceIoPollAsync(int id, u32 address) {
2012-11-01 15:19:01 +00:00
u32 error;
FileNode *f = kernelObjects.Get < FileNode > (id, error);
if (f) {
2012-11-27 09:18:36 +00:00
u64 res = f->asyncResult;
if (defAction) {
2012-11-27 09:18:36 +00:00
res = defAction(id, defParam);
2012-11-01 15:19:01 +00:00
defAction = 0;
}
Memory::Write_U64(res, address);
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "%i = sceIoPollAsync(%i, %08x) (HACK)", (u32) res, id, address);
return 0; //completed
} else {
ERROR_LOG(HLE, "ERROR - sceIoPollAsync waiting for invalid id %i", id);
return -1; // TODO: correct error code
2012-11-01 15:19:01 +00:00
}
}
class DirListing : public KernelObject {
2012-11-01 15:19:01 +00:00
public:
const char *GetName() {return name.c_str();}
const char *GetTypeName() {return "DirListing";}
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; }
int GetIDType() const { return PPSSPP_KERNEL_TMID_DirList; }
virtual void DoState(PointerWrap &p) {
p.Do(name);
p.Do(index);
// TODO: Is this the right way for it to wake up?
int count = (int) listing.size();
p.Do(count);
listing.resize(count);
for (int i = 0; i < count; ++i) {
listing[i].DoState(p);
}
p.DoMarker("DirListing");
}
2012-11-01 15:19:01 +00:00
std::string name;
std::vector<PSPFileInfo> listing;
int index;
};
u32 sceIoDopen(const char *path) {
DEBUG_LOG(HLE, "sceIoDopen(\"%s\")", path);
2012-11-01 15:19:01 +00:00
if(!pspFileSystem.GetFileInfo(path).exists)
{
return ERROR_ERRNO_FILE_NOT_FOUND;
}
2012-11-01 15:19:01 +00:00
DirListing *dir = new DirListing();
SceUID id = kernelObjects.Create(dir);
dir->listing = pspFileSystem.GetDirListing(path);
dir->index = 0;
dir->name = std::string(path);
return id;
2012-11-01 15:19:01 +00:00
}
u32 sceIoDread(int id, u32 dirent_addr) {
2012-11-01 15:19:01 +00:00
u32 error;
DirListing *dir = kernelObjects.Get<DirListing>(id, error);
if (dir) {
SceIoDirEnt *entry = (SceIoDirEnt*) Memory::GetPointer(dirent_addr);
if (dir->index == (int) dir->listing.size()) {
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "sceIoDread( %d %08x ) - end of the line", id, dirent_addr);
entry->d_name[0] = '\0';
return 0;
2012-11-01 15:19:01 +00:00
}
PSPFileInfo &info = dir->listing[dir->index];
__IoGetStat(&entry->d_stat, info);
strncpy(entry->d_name, info.name.c_str(), 256);
entry->d_name[255] = '\0';
2012-11-01 15:19:01 +00:00
entry->d_private = 0xC0DEBABE;
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "sceIoDread( %d %08x ) = %s", id, dirent_addr, entry->d_name);
2012-11-01 15:19:01 +00:00
dir->index++;
return 1;
} else {
2013-01-17 08:44:35 +00:00
DEBUG_LOG(HLE, "sceIoDread - invalid listing %i, error %08x", id, error);
return SCE_KERNEL_ERROR_BADF;
2012-11-01 15:19:01 +00:00
}
}
u32 sceIoDclose(int id) {
DEBUG_LOG(HLE, "sceIoDclose(%d)", id);
return kernelObjects.Destroy<DirListing>(id);
2012-11-01 15:19:01 +00:00
}
u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen)
{
2012-12-21 09:18:52 +00:00
u32 error;
FileNode *f = kernelObjects.Get<FileNode>(id, error);
if (error) {
return error;
}
//KD Hearts:
//56:46:434 HLE\sceIo.cpp:886 E[HLE]: UNIMPL 0=sceIoIoctrl id: 0000011f, cmd 04100001, indataPtr 08b313d8, inlen 00000010, outdataPtr 00000000, outLen 0
// 0000000
// TODO: This kind of stuff should be moved to the devices (wherever that would be)
// and does not belong in this file. Same thing with Devctl.
2012-12-21 09:18:52 +00:00
switch (cmd) {
2013-01-17 08:44:35 +00:00
// Define decryption key (amctrl.prx DRM)
case 0x04100001:
2012-12-21 09:18:52 +00:00
if (Memory::IsValidAddress(indataPtr) && inlen == 16) {
u8 keybuf[16];
2013-02-24 08:28:40 +00:00
u8 pgd_header[0x90];
2013-02-25 15:31:32 +00:00
INFO_LOG(HLE, "Decrypting PGD DRM files");
2012-12-21 09:18:52 +00:00
memcpy(keybuf, Memory::GetPointer(indataPtr), 16);
2013-02-24 08:28:40 +00:00
pspFileSystem.ReadFile(f->handle, pgd_header, 0x90);
f->pgdInfo = pgd_open(pgd_header, 2, keybuf);
if(f->pgdInfo==NULL){
DEBUG_LOG(HLE, "Not a valid PGD file. Open as normal file.");
f->npdrm = false;
pspFileSystem.SeekFile(f->handle, (s32)0, FILEMOVE_BEGIN);
}
f->asyncResult = 0;
2012-12-21 09:18:52 +00:00
}
break;
2013-01-17 08:44:35 +00:00
// Get UMD sector size
case 0x01020003:
INFO_LOG(HLE, "sceIoIoCtl: Asked for sector size of file %i", id);
if (Memory::IsValidAddress(outdataPtr) && outlen == 4) {
Memory::Write_U32(f->info.sectorSize, outdataPtr);
}
break;
// Get UMD file pointer
case 0x01020004:
INFO_LOG(HLE, "sceIoIoCtl: Asked for fpointer of file %i", id);
if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) {
Memory::Write_U32(f->info.fpointer, outdataPtr);
}
break;
// Get UMD file start sector .
case 0x01020006:
INFO_LOG(HLE, "sceIoIoCtl: Asked for start sector of file %i", id);
if (Memory::IsValidAddress(outdataPtr) && outlen >= 4) {
Memory::Write_U32(f->info.startSector, outdataPtr);
}
break;
2013-01-17 08:44:35 +00:00
// Get UMD file size in bytes.
case 0x01020007:
INFO_LOG(HLE, "sceIoIoCtl: Asked for size of file %i", id);
if (Memory::IsValidAddress(outdataPtr) && outlen >= 8) {
2013-01-17 08:44:35 +00:00
Memory::Write_U64(f->info.size, outdataPtr);
}
break;
default:
ERROR_LOG(HLE, "UNIMPL 0=sceIoIoctl id: %08x, cmd %08x, indataPtr %08x, inlen %08x, outdataPtr %08x, outLen %08x", id,cmd,indataPtr,inlen,outdataPtr,outlen);
break;
2012-12-21 09:18:52 +00:00
}
return 0;
}
2013-01-17 08:44:35 +00:00
u32 sceIoIoctlAsync(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen)
{
DEBUG_LOG(HLE, "sceIoIoctlAsync(%08x, %08x, %08x, %08x, %08x, %08x)", id, cmd, indataPtr, inlen, outdataPtr, outlen);
sceIoIoctl(id, cmd, indataPtr, inlen, outdataPtr, outlen);
__IoCompleteAsyncIO(id);
return 0;
}
KernelObject *__KernelFileNodeObject() {
return new FileNode;
}
KernelObject *__KernelDirListingObject() {
return new DirListing;
}
const HLEFunction IoFileMgrForUser[] = {
{ 0xb29ddf9c, &WrapU_C<sceIoDopen>, "sceIoDopen" },
{ 0xe3eb004c, &WrapU_IU<sceIoDread>, "sceIoDread" },
{ 0xeb092469, &WrapU_I<sceIoDclose>, "sceIoDclose" },
2013-01-17 08:44:35 +00:00
{ 0xe95a012b, &WrapU_UUUUUU<sceIoIoctlAsync>, "sceIoIoctlAsync" },
{ 0x63632449, &WrapU_UUUUUU<sceIoIoctl>, "sceIoIoctl" },
{ 0xace946e8, &WrapU_CU<sceIoGetstat>, "sceIoGetstat" },
{ 0xb8a740f4, 0, "sceIoChstat" },
{ 0x55f4717d, &WrapU_C<sceIoChdir>, "sceIoChdir" },
2013-01-17 08:44:35 +00:00
{ 0x08bd7374, &WrapU_I<sceIoGetDevType>, "sceIoGetDevType" },
{ 0xB2A628C1, &WrapU_UUUIUI<sceIoAssign>, "sceIoAssign" },
{ 0xe8bc6571, &WrapU_I<sceIoCancel>, "sceIoCancel" },
{ 0xb293727f, &WrapI_II<sceIoChangeAsyncPriority>, "sceIoChangeAsyncPriority" },
{ 0x810C4BC3, &WrapU_I<sceIoClose>, "sceIoClose" }, //(int fd);
{ 0xff5940b6, &WrapI_I<sceIoCloseAsync>, "sceIoCloseAsync" },
{ 0x54F5FB11, &WrapU_CIUIUI<sceIoDevctl>, "sceIoDevctl" }, //(const char *name int cmd, void *arg, size_t arglen, void *buf, size_t *buflen);
{ 0xcb05f8d6, &WrapU_IUU<sceIoGetAsyncStat>, "sceIoGetAsyncStat" },
{ 0x27EB27B8, &WrapI64_II64I<sceIoLseek>, "sceIoLseek" }, //(int fd, int offset, int whence);
{ 0x68963324, &WrapU_III<sceIoLseek32>, "sceIoLseek32" },
{ 0x1b385d8f, &WrapU_III<sceIoLseek32Async>, "sceIoLseek32Async" },
{ 0x71b19e77, &WrapU_II64I<sceIoLseekAsync>, "sceIoLseekAsync" },
{ 0x109F50BC, &WrapU_CII<sceIoOpen>, "sceIoOpen" }, //(const char* file, int mode);
{ 0x89AA9906, &WrapU_CII<sceIoOpenAsync>, "sceIoOpenAsync" },
{ 0x06A70004, &WrapU_CI<sceIoMkdir>, "sceIoMkdir" }, //(const char *dir, int mode);
{ 0x3251ea56, &WrapU_IU<sceIoPollAsync>, "sceIoPollAsync" },
{ 0x6A638D83, &WrapU_IUI<sceIoRead>, "sceIoRead" }, //(int fd, void *data, int size);
{ 0xa0b5a7c2, &WrapU_IUI<sceIoReadAsync>, "sceIoReadAsync" },
{ 0xF27A9C51, &WrapU_C<sceIoRemove>, "sceIoRemove" }, //(const char *file);
{ 0x779103A0, &WrapU_CC<sceIoRename>, "sceIoRename" }, //(const char *oldname, const char *newname);
{ 0x1117C65F, &WrapU_C<sceIoRmdir>, "sceIoRmdir" }, //(const char *dir);
{ 0xA12A0514, &WrapU_IUU<sceIoSetAsyncCallback>, "sceIoSetAsyncCallback" },
2013-01-17 08:44:35 +00:00
{ 0xab96437f, &WrapU_CI<sceIoSync>, "sceIoSync" },
{ 0x6d08a871, &WrapU_C<sceIoUnassign>, "sceIoUnassign" },
{ 0x42EC03AC, &WrapU_IVI<sceIoWrite>, "sceIoWrite" }, //(int fd, void *data, int size);
2013-01-17 08:44:35 +00:00
{ 0x0facab19, &WrapU_IVI<sceIoWriteAsync>, "sceIoWriteAsync" },
2012-12-26 07:02:53 +00:00
{ 0x35dbd746, &WrapI_IU<sceIoWaitAsyncCB>, "sceIoWaitAsyncCB" },
{ 0xe23eec33, &WrapI_IU<sceIoWaitAsync>, "sceIoWaitAsync" },
2012-11-01 15:19:01 +00:00
};
void Register_IoFileMgrForUser() {
2012-11-01 15:19:01 +00:00
RegisterModule("IoFileMgrForUser", ARRAY_SIZE(IoFileMgrForUser), IoFileMgrForUser);
}
const HLEFunction StdioForUser[] = {
{ 0x172D316E, &WrapU_V<sceKernelStdin>, "sceKernelStdin" },
{ 0xA6BAB2E9, &WrapU_V<sceKernelStdout>, "sceKernelStdout" },
{ 0xF78BA90A, &WrapU_V<sceKernelStderr>, "sceKernelStderr" },
2012-11-01 15:19:01 +00:00
};
void Register_StdioForUser() {
2012-11-01 15:19:01 +00:00
RegisterModule("StdioForUser", ARRAY_SIZE(StdioForUser), StdioForUser);
}