aboutsummaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/fs/psp/psp-fs-factory.cpp8
-rw-r--r--backends/fs/psp/psp-fs.cpp62
-rw-r--r--backends/fs/psp/psp-stream.cpp230
-rw-r--r--backends/fs/psp/psp-stream.h70
-rw-r--r--backends/module.mk1
-rw-r--r--backends/platform/psp/Makefile5
-rw-r--r--backends/platform/psp/module.mk1
-rw-r--r--backends/platform/psp/osys_psp.cpp1
-rw-r--r--backends/platform/psp/osys_psp.h5
-rw-r--r--backends/platform/psp/powerman.cpp297
-rw-r--r--backends/platform/psp/powerman.h87
-rw-r--r--backends/platform/psp/psp.spec2
-rw-r--r--backends/platform/psp/psp_main.cpp29
13 files changed, 784 insertions, 14 deletions
diff --git a/backends/fs/psp/psp-fs-factory.cpp b/backends/fs/psp/psp-fs-factory.cpp
index 27bee4de86..7ed84de034 100644
--- a/backends/fs/psp/psp-fs-factory.cpp
+++ b/backends/fs/psp/psp-fs-factory.cpp
@@ -34,7 +34,13 @@ AbstractFSNode *PSPFilesystemFactory::makeRootFileNode() const {
AbstractFSNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() const {
char buf[MAXPATHLEN];
- return getcwd(buf, MAXPATHLEN) ? new PSPFilesystemNode(buf) : NULL;
+ char * ret = 0;
+
+ PowerMan.beginCriticalSection();
+ ret = getcwd(buf, MAXPATHLEN);
+ PowerMan.endCriticalSection();
+
+ return (ret ? new PSPFilesystemNode(buf) : NULL);
}
AbstractFSNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const {
diff --git a/backends/fs/psp/psp-fs.cpp b/backends/fs/psp/psp-fs.cpp
index f5ff65c9fa..03247e86ad 100644
--- a/backends/fs/psp/psp-fs.cpp
+++ b/backends/fs/psp/psp-fs.cpp
@@ -26,7 +26,8 @@
#include "engines/engine.h"
#include "backends/fs/abstract-fs.h"
-#include "backends/fs/stdiostream.h"
+#include "backends/fs/psp/psp-stream.h"
+#include "backends/platform/psp/powerman.h"
#include <sys/stat.h>
#include <unistd.h>
@@ -35,6 +36,9 @@
#define ROOT_PATH "ms0:/"
+#include "backends/platform/psp/trace.h"
+
+
/**
* Implementation of the ScummVM file system API based on PSPSDK API.
*
@@ -61,13 +65,13 @@ public:
*/
PSPFilesystemNode(const Common::String &p, bool verify = true);
- virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; }
+ virtual bool exists() const;
virtual Common::String getDisplayName() const { return _displayName; }
virtual Common::String getName() const { return _displayName; }
virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
- virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; }
- virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; }
+ virtual bool isReadable() const;
+ virtual bool isWritable() const;
virtual AbstractFSNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
@@ -94,11 +98,44 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) {
if (verify) {
struct stat st;
+ PowerMan.beginCriticalSection();
_isValid = (0 == stat(_path.c_str(), &st));
+ PowerMan.endCriticalSection();
_isDirectory = S_ISDIR(st.st_mode);
}
}
+bool PSPFilesystemNode::exists() const {
+ int ret = 0;
+
+ PowerMan.beginCriticalSection(); // Make sure to block in case of suspend
+ ret = access(_path.c_str(), F_OK);
+ PowerMan.endCriticalSection();
+
+ return ret == 0;
+}
+
+bool PSPFilesystemNode::isReadable() const {
+ int ret = 0;
+
+ PowerMan.beginCriticalSection(); // Make sure to block in case of suspend
+ ret = access(_path.c_str(), R_OK);
+ PowerMan.endCriticalSection();
+
+ return ret == 0;
+}
+
+bool PSPFilesystemNode::isWritable() const {
+ int ret = 0;
+
+ PowerMan.beginCriticalSection(); // Make sure to block in case of suspend
+ ret = access(_path.c_str(), W_OK);
+ PowerMan.endCriticalSection();
+
+ return ret == 0;
+}
+
+
AbstractFSNode *PSPFilesystemNode::getChild(const Common::String &n) const {
// FIXME: Pretty lame implementation! We do no error checking to speak
// of, do not check if this is a special node, etc.
@@ -117,6 +154,10 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
//TODO: honor the hidden flag
+ bool ret = true;
+
+ PowerMan.beginCriticalSection(); // Make sure to block in case of suspend
+
int dfd = sceIoDopen(_path.c_str());
if (dfd > 0) {
SceIoDirent dir;
@@ -149,10 +190,13 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
}
sceIoDclose(dfd);
- return true;
- } else {
- return false;
+ ret = true;
+ } else { // dfd <= 0
+ ret = false;
}
+
+ PowerMan.endCriticalSection();
+ return ret;
}
AbstractFSNode *PSPFilesystemNode::getParent() const {
@@ -166,11 +210,11 @@ AbstractFSNode *PSPFilesystemNode::getParent() const {
}
Common::SeekableReadStream *PSPFilesystemNode::createReadStream() {
- return StdioStream::makeFromPath(getPath().c_str(), false);
+ return PSPIoStream::makeFromPath(getPath(), false);
}
Common::WriteStream *PSPFilesystemNode::createWriteStream() {
- return StdioStream::makeFromPath(getPath().c_str(), true);
+ return PSPIoStream::makeFromPath(getPath(), true);
}
#endif //#ifdef __PSP__
diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp
new file mode 100644
index 0000000000..fac4067f46
--- /dev/null
+++ b/backends/fs/psp/psp-stream.cpp
@@ -0,0 +1,230 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifdef __PSP__
+
+#include "backends/fs/psp/psp-stream.h"
+#include "backends/platform/psp/trace.h"
+#include <errno.h>
+
+PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode)
+: StdioStream((void *)1), _path(path), _writeMode(writeMode) {
+
+ assert(!path.empty());
+
+ _handle = (void *)0; // Need to do this since base class asserts not 0.
+
+ PowerMan.registerSuspend(this); // Register with the powermanager to be suspended
+
+}
+
+PSPIoStream::~PSPIoStream() {
+ PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended
+ // Must do this before fclose() or resume() will reopen.
+
+ fclose((FILE *)_handle);
+}
+
+// Function to open the file pointed to by the path.
+//
+//
+void * PSPIoStream::open() {
+ if (PowerMan.beginCriticalSection()==PowerManager::Blocked) {
+ // No need to open. Just return the _handle resume() already opened.
+ PSPDebugTrace("Suspended in PSPIoStream::open\n");
+ } else {
+ _handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open
+ }
+
+ PowerMan.endCriticalSection();
+
+ return _handle;
+}
+
+bool PSPIoStream::err() const {
+ bool ret;
+
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::err()\n");
+
+ ret = ferror((FILE *)_handle) != 0;
+
+ PowerMan.endCriticalSection();
+
+ return ret;
+}
+
+void PSPIoStream::clearErr() {
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::clearErr()\n");
+
+ clearerr((FILE *)_handle);
+
+ PowerMan.endCriticalSection();
+}
+
+bool PSPIoStream::eos() const {
+ bool ret;
+
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::eos()\n");
+
+ ret = feof((FILE *)_handle) != 0;
+
+ PowerMan.endCriticalSection();
+
+ return ret;
+}
+
+int32 PSPIoStream::pos() const {
+ int32 ret;
+
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::pos()\n");
+
+ ret = ftell((FILE *)_handle);
+
+ PowerMan.endCriticalSection();
+
+ return ret;
+}
+
+
+int32 PSPIoStream::size() const {
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::size()\n");
+
+ int32 oldPos = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, 0, SEEK_END);
+ int32 length = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, oldPos, SEEK_SET);
+
+ PowerMan.endCriticalSection();
+
+ return length;
+}
+
+bool PSPIoStream::seek(int32 offs, int whence) {
+ int ret = 0;
+
+ // Check if we can access the file
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::seek()\n");
+
+ ret = fseek((FILE *)_handle, offs, whence);
+
+ PowerMan.endCriticalSection();
+
+ return ret == 0;
+}
+
+uint32 PSPIoStream::read(void *ptr, uint32 len) {
+ int ret = 0;
+
+ // Check if we can access the file
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+
+ ret = fread((byte *)ptr, 1, len, (FILE *)_handle);
+
+ PowerMan.endCriticalSection();
+
+ return ret;
+}
+
+uint32 PSPIoStream::write(const void *ptr, uint32 len) {
+ int ret = 0;
+
+ // Check if we can access the file
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+
+ ret = fwrite(ptr, 1, len, (FILE *)_handle);
+
+ PowerMan.endCriticalSection();
+
+ return ret;
+}
+
+bool PSPIoStream::flush() {
+ int ret = 0;
+
+ // Check if we can access the file
+ if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+ PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+
+ ret = fflush((FILE *)_handle);
+
+ PowerMan.endCriticalSection();
+
+ return ret == 0;
+}
+
+// For the PSP, since we're building in suspend support, we moved opening
+// the actual file to an open function since we need an actual PSPIoStream object to suspend.
+//
+PSPIoStream *PSPIoStream::makeFromPath(const Common::String &path, bool writeMode) {
+ PSPIoStream *stream = new PSPIoStream(path, writeMode);
+
+ if (stream->open() > 0) {
+ return stream;
+ } else {
+ delete stream;
+ return 0;
+ }
+}
+
+/*
+ * Function to suspend the IO stream (called by PowerManager)
+ */
+int PSPIoStream::suspend() {
+ if (_handle > 0) {
+ _pos = ftell((FILE *)_handle); // Save our position
+ fclose((FILE *)_handle); // close our file descriptor
+ _handle = 0; // Set handle to null
+ }
+
+ return 0;
+}
+
+/*
+ * Function to resume the IO stream (called by Power Manager)
+ */
+int PSPIoStream::resume() {
+ int ret = 0;
+
+ // We reopen our file descriptor
+ _handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb");
+ if (_handle <= 0) {
+ PSPDebugTrace("PSPIoStream::resume(): Couldn't reopen file %s\n", _path.c_str());
+ ret = -1;;
+ }
+
+ // Resume our previous position
+ if(_handle > 0) fseek((FILE *)_handle, _pos, SEEK_SET);
+
+ return ret;
+}
+
+#endif /* __PSP__ */
diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h
new file mode 100644
index 0000000000..0363c92416
--- /dev/null
+++ b/backends/fs/psp/psp-stream.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef PSPSTREAM_H_
+#define PSPSTREAM_H_
+
+#include "backends/fs/stdiostream.h"
+#include "backends/platform/psp/powerman.h"
+#include "common/list.h"
+
+/*
+ * Class to handle special suspend/resume needs of PSP IO Streams
+ */
+class PSPIoStream : public StdioStream, public Suspendable {
+protected:
+ Common::String _path; /* Need to maintain for reopening after suspend */
+ bool _writeMode; /* "" */
+ unsigned int _pos; /* "" */
+
+public:
+ /**
+ * Given a path, invoke fopen on that path and wrap the result in a
+ * PSPIoStream instance.
+ */
+ static PSPIoStream *makeFromPath(const Common::String &path, bool writeMode);
+
+ PSPIoStream(const Common::String &path, bool writeMode);
+ virtual ~PSPIoStream();
+
+ void * open(); // open the file pointed to by the file path
+
+ bool err() const;
+ void clearErr();
+ bool eos() const;
+
+ virtual uint32 write(const void *dataPtr, uint32 dataSize);
+ virtual bool flush();
+
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ virtual bool seek(int32 offs, int whence = SEEK_SET);
+ virtual uint32 read(void *dataPtr, uint32 dataSize);
+
+ int suspend(); /* Suspendable interface (power manager) */
+ int resume(); /* " " */
+};
+
+#endif /* PSPSTREAM_H_ */
diff --git a/backends/module.mk b/backends/module.mk
index f3294c5dc6..42fbeb07eb 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS := \
fs/posix/posix-fs-factory.o \
fs/ps2/ps2-fs-factory.o \
fs/psp/psp-fs-factory.o \
+ fs/psp/psp-stream.o \
fs/symbian/symbian-fs-factory.o \
fs/windows/windows-fs-factory.o \
fs/wii/wii-fs-factory.o \
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 91a0c60bd6..ad22a853e1 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -75,12 +75,13 @@ LIBS += -lmad
CXXFLAGS+= -DUSE_VORBIS -DUSE_TREMOR
LIBS += -lvorbisidec
-LIBS += `$(PSPBIN)/sdl-config --libs` -lz -lstdc++ -lc -lpspdisplay -lpspgu -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpsputility -lpspsdk -lpspuser
+LIBS += `$(PSPBIN)/sdl-config --libs` -lz -lstdc++ -lc -lpspdisplay -lpspgu -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpsputility -lpspuser -lpsppower
CXXFLAGS := $(CXXFLAGS) -fno-exceptions -fno-rtti
TARGET = scummvm-psp
-OBJS := psp_main.o \
+OBJS := powerman.o \
+ psp_main.o \
osys_psp.o \
osys_psp_gu.o \
kbd_ss_c.o \
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index afe9a23f58..8f083c5dfa 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -1,6 +1,7 @@
MODULE := backends/platform/psp
MODULE_OBJS := \
+ powerman.o \
psp_main.o \
osys_psp.o \
osys_psp_gu.o \
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index 45be0a0cd3..8a7a0af0ed 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -430,6 +430,7 @@ bool OSystem_PSP::pollEvent(Common::Event &event) {
} else if (buttonsChanged & PSP_CTRL_START) {
event.kbd.keycode = Common::KEYCODE_F5;
event.kbd.ascii = Common::ASCII_F5;
+ event.kbd.flags = Common::KBD_CTRL; // Main menu to allow RTL
/* } else if (buttonsChanged & PSP_CTRL_SELECT) {
event.kbd.keycode = Common::KEYCODE_0;
event.kbd.ascii = '0';
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 34957b293c..46607dac34 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -23,6 +23,9 @@
*
*/
+#ifndef OSYS_PSP_H
+#define OSYS_PSP_H
+
#include "common/scummsys.h"
#include "graphics/surface.h"
#include "graphics/colormasks.h"
@@ -144,3 +147,5 @@ public:
virtual Common::WriteStream *createConfigWriteStream();
};
+
+#endif /* OSYS_PSP_H */
diff --git a/backends/platform/psp/powerman.cpp b/backends/platform/psp/powerman.cpp
new file mode 100644
index 0000000000..c553669fc3
--- /dev/null
+++ b/backends/platform/psp/powerman.cpp
@@ -0,0 +1,297 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "./powerman.h"
+#include "./trace.h"
+
+DECLARE_SINGLETON(PowerManager);
+
+ /*******************************************
+*
+* Constructor
+*
+********************************************/
+PowerManager::PowerManager() {
+ _flagMutex = NULL; /* Init mutex handle */
+ _listMutex = NULL; /* Init mutex handle */
+ _condSuspendable = NULL; /* Init condition variable */
+ _condPM = NULL;
+
+ _condSuspendable = SDL_CreateCond();
+ if (_condSuspendable <= 0) {
+ PSPDebugTrace("PowerManager::PowerManager(): Couldn't create condSuspendable\n");
+ }
+
+ _condPM = SDL_CreateCond();
+ if (_condPM <= 0) {
+ PSPDebugTrace("PowerManager::PowerManager(): Couldn't create condPM\n");
+ }
+
+ _flagMutex = SDL_CreateMutex();
+ if (_flagMutex <= 0) {
+ PSPDebugTrace("PowerManager::PowerManager(): Couldn't create flagMutex\n");
+ }
+
+ _listMutex = SDL_CreateMutex();
+ if (_listMutex <= 0) {
+ PSPDebugTrace("PowerManager::PowerManager(): Couldn't create listMutex\n");
+ }
+
+ _suspendFlag = false;
+ _criticalCounter = 0;
+ }
+
+/*******************************************
+*
+* Function to register to be notified when suspend/resume time comes
+*
+********************************************/
+int PowerManager::registerSuspend(Suspendable *item) {
+ // Register in list
+ PSPDebugTrace("In registerSuspend\n");
+
+ if (SDL_mutexP(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::registerSuspend(): Couldn't lock _listMutex %d\n", _listMutex);
+ }
+
+ _suspendList.push_front(item);
+
+ if (SDL_mutexV(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::registerSuspend(): Couldn't unlock _listMutex %d\n", _listMutex);
+ }
+
+ PSPDebugTrace("Out of registerSuspend\n");
+
+ return 0;
+}
+
+/*******************************************
+*
+* Function to unregister to be notified when suspend/resume time comes
+*
+********************************************/
+int PowerManager::unregisterSuspend(Suspendable *item) {
+
+ PSPDebugTrace("In unregisterSuspend\n");
+
+ // Unregister from stream list
+ if (SDL_mutexP(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::unregisterSuspend(): Couldn't unlock _listMutex %d\n", _listMutex);
+ }
+
+ _suspendList.remove(item);
+
+ if (SDL_mutexV(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::unregisterSuspend(): Couldn't unlock _listMutex %d\n", _listMutex);
+ }
+
+ PSPDebugTrace("Out of unregisterSuspend\n");
+
+ return 0;
+ }
+
+ /*******************************************
+*
+* Destructor
+*
+********************************************/
+ PowerManager::~PowerManager() {
+ SDL_DestroyCond(_condSuspendable);
+ _condSuspendable = 0;
+
+ SDL_DestroyCond(_condPM);
+ _condPM = 0;
+
+ SDL_DestroyMutex(_flagMutex);
+ _flagMutex = 0;
+
+ SDL_DestroyMutex(_listMutex);
+ _listMutex = 0;
+ }
+
+
+ /*******************************************
+*
+* Function to be called by threads wanting to block on the PSP entering suspend
+*
+********************************************/
+ int PowerManager::blockOnSuspend() {
+ return beginCriticalSection(true);
+}
+
+ /*
+ * Function to block on a suspend, then start a non-suspendable critical section
+ */
+int PowerManager::beginCriticalSection(bool justBlock) {
+ int ret = PowerManager::NotBlocked;
+
+ if (SDL_mutexP(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't lock flagMutex %d\n", _flagMutex);
+ ret = PowerManager::Error;
+ }
+
+ // Check the access flag
+ if (_suspendFlag == true) {
+ PSPDebugTrace("Blocking!!\n");
+ ret = PowerManager::Blocked;
+
+ // If it's true, we wait for a signal to continue
+ if( SDL_CondWait(_condSuspendable, _flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't wait on cond %d\n", _condSuspendable);
+ }
+
+ PSPDebugTrace("We got blocked!!\n");
+ }
+
+ // Now put the pm to sleep
+ if (justBlock == false)
+ _criticalCounter++;
+
+ if (SDL_mutexV(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't unlock flagMutex %d\n", _flagMutex);
+ ret = PowerManager::Error;
+ }
+
+ return ret;
+}
+
+int PowerManager::endCriticalSection() {
+ int ret = 0;
+
+ if (SDL_mutexP(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::endCriticalSection(): Couldn't lock flagMutex %d\n", _flagMutex);
+ ret = PowerManager::Error;
+ }
+
+ // We're done with our critical section
+ _criticalCounter--;
+
+ if (_criticalCounter <= 0) {
+ if(_suspendFlag == true) PSPDebugTrace("Waking up the PM and suspendFlag is true\n");
+
+ SDL_CondBroadcast(_condPM);
+
+ if (_criticalCounter < 0) {
+ PSPDebugTrace("PowerManager::endCriticalSection(): Error! Critical counter is %d\n", _criticalCounter);
+ }
+ }
+
+ if (SDL_mutexV(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::endCriticalSection(): Couldn't unlock flagMutex %d\n", _flagMutex);
+ ret = PowerManager::Error;
+ }
+
+ return ret;
+}
+
+ /*******************************************
+*
+* Callback function to be called to put every Suspendable to suspend
+*
+********************************************/
+int PowerManager::suspend() {
+ int ret = 0;
+
+ // First we set the suspend flag to true
+ if (SDL_mutexP(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::suspend(): Couldn't lock flagMutex %d\n", _flagMutex);
+ ret = -1;
+ }
+
+ _suspendFlag = true;
+
+ if (_criticalCounter > 0)
+ SDL_CondWait(_condPM, _flagMutex);
+
+ if (SDL_mutexV(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::suspend(): Couldn't unlock flagMutex %d\n", _flagMutex);
+ ret = -1;
+ }
+
+ // Loop over list, calling suspend()
+ if (SDL_mutexP(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::suspend(): Couldn't lock listMutex %d\n", _listMutex);
+ ret = -1;
+ }
+
+ Common::List<Suspendable *>::iterator i = _suspendList.begin();
+
+ for (; i != _suspendList.end(); i++) {
+ (*i)->suspend();
+ }
+
+ if (SDL_mutexV(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::suspend(): Couldn't unlock listMutex %d\n", _listMutex);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*******************************************
+*
+* Callback function to resume every Suspendable
+*
+********************************************/
+int PowerManager::resume() {
+ int ret = 0;
+
+ // First we notify our Suspendables. Loop over list, calling resume()
+ if (SDL_mutexP(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::resume(): Couldn't lock listMutex %d\n", _listMutex);
+ ret = -1;
+ }
+
+ Common::List<Suspendable *>::iterator i = _suspendList.begin();
+
+ for (; i != _suspendList.end(); i++) {
+ (*i)->resume();
+ }
+
+ if (SDL_mutexV(_listMutex) != 0) {
+ PSPDebugTrace("PowerManager::resume(): Couldn't unlock listMutex %d\n", _listMutex);
+ ret = -1;
+ }
+
+ // Now we set the suspend flag to false
+ if (SDL_mutexP(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::resume(): Couldn't lock flagMutex %d\n", _flagMutex);
+ ret = -1;
+ }
+ _suspendFlag = false;
+
+ // Signal the other threads to wake up
+ if (SDL_CondBroadcast(_condSuspendable) != 0) {
+ PSPDebugTrace("PowerManager::resume(): Couldn't broadcast condition %d\n", _condSuspendable);
+ ret = -1;
+ }
+
+ if (SDL_mutexV(_flagMutex) != 0) {
+ PSPDebugTrace("PowerManager::resume(): Couldn't unlock flagMutex %d\n", _flagMutex);
+ ret = -1;
+ }
+
+ return ret;
+}
diff --git a/backends/platform/psp/powerman.h b/backends/platform/psp/powerman.h
new file mode 100644
index 0000000000..0a5f7a2361
--- /dev/null
+++ b/backends/platform/psp/powerman.h
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef POWERMAN_H
+#define POWERMAN_H
+
+#include <SDL/SDL_thread.h>
+#include <SDL/SDL_mutex.h>
+#include "common/singleton.h"
+#include "common/list.h"
+
+ /*
+ * Implement this class (interface) if you want to use PowerManager's suspend callback functionality
+ *
+ */
+ class Suspendable {
+ public:
+ virtual ~Suspendable() {}
+ virtual int suspend() = 0;
+ virtual int resume() = 0;
+ };
+
+ /******************************************************************************************************
+ *
+ * This class will call a Suspendable when the PSP goes to suspend/resumes. It also provides the ability to block
+ * a thread when the PSP is going to suspend/suspending, and to wake it up when the PSP is resumed.
+ * This ability is very useful for managing the PSPIoStream class, but may be found useful by other classes as well.
+ *
+ *******************************************************************************************************/
+ class PowerManager: public Common::Singleton<PowerManager> {
+private:
+ friend class Common::Singleton<PowerManager>;
+ PowerManager();
+ ~PowerManager();
+
+ Common::List<Suspendable *> _suspendList; /* list to register in */
+
+ bool _suspendFlag; /* protected variable */
+ SDL_mutex *_flagMutex; /* mutex to access access flag */
+ SDL_mutex *_listMutex; /* mutex to access Suspendable list */
+ SDL_cond *_condSuspendable; /* signal to synchronize accessing threads */
+ SDL_cond *_condPM; /* signal to wake up the PM from a critical section */
+ int _criticalCounter; /* Counter of how many threads are in a critical section */
+
+public:
+ int blockOnSuspend(); /* block if suspending */
+ int beginCriticalSection(bool justBlock = false); /* Use a critical section to block (if suspend was already pressed) */
+ int endCriticalSection(); /* and to prevent the PSP from suspending in a particular section */
+ int registerSuspend(Suspendable *item); /* register to be called to suspend/resume */
+ int unregisterSuspend(Suspendable *item); /* remove from suspend/resume list */
+ int suspend(); /* callback to have all items in list suspend */
+ int resume(); /* callback to have all items in list resume */
+
+ enum {
+ Error = -1,
+ NotBlocked = 0,
+ Blocked = 1
+ };
+
+ };
+
+ // For easy access
+#define PowerMan PowerManager::instance()
+
+ #endif /* POWERMAN_H */
diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec
index 807b8f93b7..e319b022f7 100644
--- a/backends/platform/psp/psp.spec
+++ b/backends/platform/psp/psp.spec
@@ -1,3 +1,3 @@
%rename lib old_lib
*lib:
-%(old_lib) -lpspdebug -lpspgu -lpspctrl -lpspge -lpspdisplay -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lc -lpspuser -lpsputility -lpspkernel -lpspnet_inet -lz -lstdc++ -lc -lpspdisplay -lpspgu -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpsputility -lpspsdk -lpspuser
+%(old_lib) -lpspdebug -lpspgu -lpspctrl -lpspge -lpspdisplay -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lc -lpspuser -lpsputility -lpspkernel -lpspnet_inet -lz -lstdc++ -lc -lpspdisplay -lpspgu -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpsputility -lpspuser -lpsppower
diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp
index 0af7ebf269..37080c7bf9 100644
--- a/backends/platform/psp/psp_main.cpp
+++ b/backends/platform/psp/psp_main.cpp
@@ -31,10 +31,14 @@
#include <pspdebug.h>
#endif
+#include <psppower.h>
+
#include <common/system.h>
#include <engines/engine.h>
#include <base/main.h>
#include <base/plugins.h>
+#include "backends/platform/psp/powerman.h"
+
#include "osys_psp_gu.h"
#include "./trace.h"
@@ -91,17 +95,36 @@ void loaderInit() {
#endif
/* Exit callback */
-SceKernelCallbackFunction exit_callback(int /*arg1*/, int /*arg2*/, void * /*common*/) {
+int exit_callback(void) {
sceKernelExitGame();
return 0;
}
+/* Function for handling suspend/resume */
+void power_callback(int , int powerinfo) {
+ if (powerinfo & PSP_POWER_CB_POWER_SWITCH || powerinfo & PSP_POWER_CB_SUSPENDING) {
+ PowerMan.suspend();
+ } else if (powerinfo & PSP_POWER_CB_RESUME_COMPLETE) {
+ PowerMan.resume();
+ }
+}
+
/* Callback thread */
int CallbackThread(SceSize /*size*/, void *arg) {
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", (SceKernelCallbackFunction)exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
+ /* Set up callbacks for PSPIoStream */
+
+ cbid = sceKernelCreateCallback("Power Callback", (SceKernelCallbackFunction)power_callback, 0);
+ if (cbid >= 0) {
+ if(scePowerRegisterCallback(-1, cbid) < 0) {
+ PSPDebugTrace("SetupCallbacks(): Couldn't register callback for power_callback\n");
+ }
+ } else {
+ PSPDebugTrace("SetupCallbacks(): Couldn't create a callback for power_callback\n");
+ }
sceKernelSleepThreadCB();
return 0;
@@ -119,6 +142,8 @@ int SetupCallbacks(void) {
#undef main
int main(void) {
+ PowerManager::instance(); // Setup power manager
+
SetupCallbacks();
static const char *argv[] = { "scummvm", NULL };
@@ -131,6 +156,8 @@ int main(void) {
g_system->quit(); // TODO: Consider removing / replacing this!
+ PowerManager::destroy(); // get rid of PowerManager
+
sceKernelSleepThread();
return res;