[Scummvm-cvs-logs] SF.net SVN: scummvm: [23452] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Thu Jul 20 22:40:00 CEST 2006


Revision: 23452
          http://svn.sourceforge.net/scummvm/?rev=23452&view=rev
Author:   fingolfin
Date:     2006-07-09 04:47:17 -0700 (Sun, 09 Jul 2006)

Log Message:
-----------
Patch #1519399: DS Backend

Modified Paths:
--------------
    scummvm/trunk/common/scummsys.h
    scummvm/trunk/engines/scumm/dialogs.cpp
    scummvm/trunk/engines/scumm/gfx.cpp
    scummvm/trunk/engines/scumm/thumbnail.cpp
    scummvm/trunk/gui/options.cpp
    scummvm/trunk/sound/fmopl.cpp

Added Paths:
-----------
    scummvm/trunk/backends/fs/ds/
    scummvm/trunk/backends/fs/ds/ds-fs.cpp
    scummvm/trunk/backends/fs/ds/ds-fs.h
    scummvm/trunk/backends/platform/ds/
    scummvm/trunk/backends/platform/ds/arm7/
    scummvm/trunk/backends/platform/ds/arm7/Makefile
    scummvm/trunk/backends/platform/ds/arm7/source/
    scummvm/trunk/backends/platform/ds/arm7/source/main.cpp
    scummvm/trunk/backends/platform/ds/arm9/
    scummvm/trunk/backends/platform/ds/arm9/buildkeyboard.bat
    scummvm/trunk/backends/platform/ds/arm9/lib/
    scummvm/trunk/backends/platform/ds/arm9/lib/readme.txt
    scummvm/trunk/backends/platform/ds/arm9/makefile
    scummvm/trunk/backends/platform/ds/arm9/source/
    scummvm/trunk/backends/platform/ds/arm9/source/blitters.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/blitters.h
    scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.h
    scummvm/trunk/backends/platform/ds/arm9/source/compressor/
    scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.h
    scummvm/trunk/backends/platform/ds/arm9/source/console2.h
    scummvm/trunk/backends/platform/ds/arm9/source/dsmain.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/dsmain.h
    scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/
    scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.c
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.h
    scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd_asm.s
    scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.h
    scummvm/trunk/backends/platform/ds/arm9/source/mad/
    scummvm/trunk/backends/platform/ds/arm9/source/mad/readme.txt
    scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.h
    scummvm/trunk/backends/platform/ds/arm9/source/portdefs.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/portdefs.h
    scummvm/trunk/backends/platform/ds/arm9/source/ramsave.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/ramsave.h
    scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.c
    scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.h
    scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.h
    scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.h
    scummvm/trunk/backends/platform/ds/arm9/source/zipreader.cpp
    scummvm/trunk/backends/platform/ds/arm9/source/zipreader.h
    scummvm/trunk/backends/platform/ds/commoninclude/
    scummvm/trunk/backends/platform/ds/commoninclude/NDS/
    scummvm/trunk/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
    scummvm/trunk/backends/platform/ds/makefile

Added: scummvm/trunk/backends/fs/ds/ds-fs.cpp
===================================================================
--- scummvm/trunk/backends/fs/ds/ds-fs.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/fs/ds/ds-fs.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,1736 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+
+#include "stdafx.h"
+#include "str.h"
+#include "fs.h"
+#include "common/util.h"
+#include <NDS/ARM9/console.h> //basic print funcionality
+#include "ds-fs.h"
+#include "dsmain.h"
+#include "gba_nds_fat.h"
+
+namespace DS {
+
+//////////////////////////////////////////////////////////////
+// DSFileSystemNode - Flash ROM file system using Zip files
+//////////////////////////////////////////////////////////////
+
+ZipFile*   	DSFileSystemNode::_zipFile = NULL;
+char		currentDir[128];
+
+DSFileSystemNode::DSFileSystemNode() {
+	_displayName = "ds:/";
+	_path = "ds:/";
+	_isValid = true;
+	_isDirectory = true;
+	_path = "ds:/";
+
+/*	if (!_archive) {
+		_archive = (GBFS_FILE *) find_first_gbfs_file(scummdata);
+		if (!_archive) consolePrintf("No GBFS archive found!\n");
+	}*/
+	
+	if (!_zipFile) {
+		_zipFile = new ZipFile();
+	}
+}
+
+DSFileSystemNode::DSFileSystemNode(const String& path) {
+//	consolePrintf("--%s ",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	
+	
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if (path[r] == '\\') {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+	
+	_displayName = String(disp);
+	_path = path;
+//	_isValid = true;
+//	_isDirectory = false;
+
+
+
+	if (!strncmp(pathStr, "ds:/", 4)) {
+		pathStr += 4;
+	}
+	
+
+	if (*pathStr == '\0') {
+		_isValid = true;
+		_isDirectory = true;
+		return;
+	}
+	
+	_zipFile->setAllFilesVisible(true);
+	if (_zipFile->findFile(pathStr)) {
+		_isValid = true;
+		_isDirectory = _zipFile->isDirectory();
+	} else {
+		_isValid = false;
+		_isDirectory = false;
+	}
+	_zipFile->setAllFilesVisible(false);
+	
+//	consolePrintf("%s - Found: %d, Dir: %d\n", pathStr, _isValid, _isDirectory);
+}
+
+DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) {
+//	consolePrintf("--%s ",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if (path[r] == '\\') {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+	
+	_displayName = String(disp);
+	_path = path;
+	_isValid = true;
+	_isDirectory = isDir;
+	
+//	consolePrintf("Found: %d, Dir: %d\n", _isValid, _isDirectory);
+}
+
+DSFileSystemNode::DSFileSystemNode(const DSFileSystemNode* node) {
+
+}
+
+AbstractFilesystemNode* DSFileSystemNode::parent() const {
+//	consolePrintf("parent\n");
+	DSFileSystemNode *p;
+
+	if (_path != "ds:/") {  
+		char *path = (char *) _path.c_str();
+		int lastSlash = 4;
+		
+		for (int r = 4; r < (int) strlen((char *) path); r++) {
+			if (path[r] == '\\') {
+				lastSlash = r;
+			}
+		}
+
+		p = new DSFileSystemNode(String(path, lastSlash));
+		((DSFileSystemNode *) (p))->_isDirectory = true;
+	} else {
+		p = new DSFileSystemNode();
+	}
+
+	return p;
+
+}
+
+
+AbstractFilesystemNode *DSFileSystemNode::child(const Common::String& name) const {
+	if (_path.lastChar() == '\\') {
+		return new DSFileSystemNode(_path + name);
+	} else {
+		return new DSFileSystemNode(_path + "\\" + name);
+	}
+	
+	return NULL;
+}
+
+
+bool DSFileSystemNode::listDir(AbstractFSList &dirList, ListMode mode) const {
+//	consolePrintf("Listdir\n");
+
+	
+//	consolePrintf("Directory\n");
+
+	
+	char temp[128];
+	strcpy(temp, _path.c_str());
+
+//	consolePrintf("This dir: %s\n", temp);
+
+	if ((temp[0] == 'd') && (temp[1] == 's') && (temp[2] == ':') && (temp[3] == '/')) {
+		if (strlen(temp) != 4) {
+			_zipFile->changeDirectory(&temp[4]);
+		} else {
+			_zipFile->changeToRoot();
+			
+/*			// This is the root dir, so add the RAM folder
+			DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/ram");
+			dsfsn->_isDirectory = true;
+			dirList->push_back(wrap(dsfsn));*/
+		}
+	} else {
+		_zipFile->changeDirectory(temp);
+	}
+	
+	
+	
+	if (_zipFile->restartFile()) {
+		do {
+			char name[128];	
+			_zipFile->getFileName(name);
+	
+//			consolePrintf("file: %s\n", name);
+			if ( (_zipFile->isDirectory() && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)) ) 
+				|| (!_zipFile->isDirectory() && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll)) ) ) 
+			{
+				DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + String(name), _zipFile->isDirectory());
+				dsfsn->_isDirectory = _zipFile->isDirectory();
+				dirList.push_back((dsfsn));
+			}
+			
+		} while (_zipFile->skipFile());
+	}
+
+	return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// GBAMPFileSystemNode - File system using GBA Movie Player and CF card
+/////////////////////////////////////////////////////////////////////////
+
+GBAMPFileSystemNode::GBAMPFileSystemNode() {
+	_displayName = "mp:/";
+	_path = "mp:/";
+	_isValid = true;
+	_isDirectory = true;
+	_path = "mp:/";
+}
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) {
+//	consolePrintf("'%s'",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if ((path[r] == '\\') || (path[r] == '/')) {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+
+	char check[128];
+	int success;
+	
+	memset(check, 0, 128);
+	if (strlen(pathStr) > 3) {
+		strcpy(check, pathStr + 3);
+		if (check[strlen(check) - 1] == '/') {
+			check[strlen(check) - 1] = 0;
+		}
+		success = FAT_FileExists(check);
+	} else {
+		success = FT_DIR;
+	}
+//	consolePrintf("Path: %s  (%d)\n", check, success);
+	
+	_displayName = String(disp);
+	_path = path;
+	_isValid = success == FT_FILE;
+	_isDirectory = success == FT_DIR;
+}
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) {
+//	consolePrintf("'%s'",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if ((path[r] == '\\') || (path[r] == '/')) {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+
+	_displayName = String(disp);
+	_path = path;
+	_isValid = true;
+	_isDirectory = isDirectory;
+}
+
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const GBAMPFileSystemNode* node) {
+
+}
+
+
+AbstractFilesystemNode* GBAMPFileSystemNode::parent() const {
+//	consolePrintf("parent\n");
+	GBAMPFileSystemNode *p;
+
+	if (_path != "mp:/") {  
+		char *path = (char *) _path.c_str();
+		int lastSlash = 4;
+		
+		for (int r = 4; r < (int) strlen((char *) path); r++) {
+			if (path[r] == '/') {
+				lastSlash = r;
+			}
+		}
+
+		p = new GBAMPFileSystemNode(String(path, lastSlash));
+		p->_isDirectory = true;
+	} else {
+		p = new GBAMPFileSystemNode();
+	}
+
+	return p;
+
+}
+
+AbstractFilesystemNode *GBAMPFileSystemNode::child(const Common::String& name) const {
+	if (_path.lastChar() == '\\') {
+		return new DSFileSystemNode(_path + name);
+	} else {
+		return new DSFileSystemNode(_path + "\\" + name);
+	}
+	
+	return NULL;
+}
+
+bool GBAMPFileSystemNode::listDir(AbstractFSList& dirList, ListMode mode) const {
+//	consolePrintf("Listdir\n");
+
+	enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
+	
+	char temp[128], fname[128], *path, *pathTemp;
+	strcpy(temp, _path.c_str());
+	
+	path = temp + 3;
+	
+	pathTemp = path;
+	while (*pathTemp) {
+		if (*pathTemp == '\\') {
+			*pathTemp = '/';
+		}
+		pathTemp++;
+	}
+
+
+//	consolePrintf("This dir: %s\n", path);
+	FAT_chdir(path);
+	
+	int entryType = FAT_FindFirstFile(fname);
+	
+	while (entryType != TYPE_NO_MORE) {
+	
+		if ( ((entryType == TYPE_DIR) && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)))
+		||   ((entryType == TYPE_FILE) && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll))) ) {
+			GBAMPFileSystemNode* dsfsn;
+			
+			if (strcmp(fname, ".") && strcmp(fname, "..")) {
+				
+				if (!strcmp(path, "/")) {
+					dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String(fname), entryType == TYPE_DIR);
+				} else {
+					dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String("/") + String(fname), entryType == TYPE_DIR);
+				}
+				
+//				dsfsn->_isDirectory = entryType == DIR;
+				dirList.push_back((dsfsn));
+			}
+		
+		
+		} else {
+//			consolePrintf("Skipping %s\n", fname);
+		}
+		
+		entryType = FAT_FindNextFile(fname);
+	}
+	
+//	consolePrintf("No more");
+	
+	FAT_chdir("/");
+
+	return true;
+}
+
+
+// Stdio replacements
+#define MAX_FILE_HANDLES 32
+
+bool inited = false;
+DS::fileHandle handle[MAX_FILE_HANDLES];
+
+FILE* std_fopen(const char* name, const char* mode) {
+
+	
+
+	if (!inited) {
+		for (int r = 0; r < MAX_FILE_HANDLES; r++) {
+			handle[r].used = false;
+		}
+		inited = true;
+		currentDir[0] = '\0';
+	}
+
+
+	
+	
+	char* realName = (char *) name;
+	
+	// Remove file system prefix
+	if ((name[0] == 'd') && (name[1] == 's') && (name[2] == ':') && (name[3] == '/')) {
+		realName += 4;
+	}
+
+	if ((name[0] == 'm') && (name[1] == 'p') && (name[2] == ':') && (name[3] == '/')) {
+		realName += 4;
+	}
+
+//	consolePrintf("Open file:");
+//	consolePrintf("'%s', [%s]", realName, mode);
+
+
+	if (DS::isGBAMPAvailable()) {
+		FAT_chdir("/");
+		
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+		FAT_FILE* result = FAT_fopen(realName, mode);
+		
+		if (result == 0) {
+//			consolePrintf("Error code %d\n", result);
+			//consolePrintf("Opening file %s\n", realName);
+		} else {
+//			consolePrintf("Opened file %d\n", result);
+		}
+//		MT_memoryReport();
+		
+		return (fileHandle *) result;
+	}
+
+	
+	// Fail to open file for writing.  It's in ROM!
+
+	// Allocate a file handle
+	int r = 0;
+	while (handle[r].used) r++;
+	
+	if (strchr(mode, 'w')) {
+//		consolePrintf("Writing %s\n", realName);
+		handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true);
+	} else {
+//		consolePrintf("Reading %s\n", realName);
+		handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false);
+	}
+
+	
+	if (handle[r].sramFile) {
+		handle[r].used = true;
+		handle[r].pos = 0;
+		handle[r].data = NULL;
+		handle[r].size = handle[r].sramFile->getSize();
+//		consolePrintf("Found it");
+		return &handle[r];
+	} 
+
+//	consolePrintf("Not in SRAM!");
+
+	char* data;
+	
+	ZipFile* zip = DSFileSystemNode::getZip();
+	if (!zip) {
+//		consolePrintf("No zip yet!");
+		return NULL;
+	}
+	
+	// Grab the data if it exists
+	
+	zip->setAllFilesVisible(true);
+	
+	if (currentDir[0] != 0) {
+		char nameWithPath[128];
+		sprintf(nameWithPath, "%s\%s", currentDir, realName);
+		strcpy(realName, nameWithPath);
+	}
+
+//	consolePrintf("fopen(%s, %s)\n", realName, name);
+		
+	if (zip->findFile(realName)) {
+		data = zip->getFile();
+		zip->setAllFilesVisible(false);
+		
+		// Allocate a file handle
+		int r = 0;
+		while (handle[r].used) r++;
+	
+	
+		handle[r].used = true;
+		handle[r].pos = 0;
+		handle[r].data = data;
+		handle[r].size = zip->getFileSize();
+
+//		consolePrintf("Opened file %d: %s (%s)   ", r, realName, name);
+		return &handle[r];
+	} else {
+		zip->setAllFilesVisible(false);
+//		consolePrintf("Not found: %s (%s)  ", realName, name);
+		return NULL;
+	}
+}
+void std_fclose(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		FAT_fclose((FAT_FILE *) handle);
+		return;
+	}
+
+	handle->used = false;
+	if (handle->sramFile) {
+		delete handle->sramFile;
+		handle->sramFile = NULL;
+	}
+}
+
+size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) {
+
+//	consolePrintf("fread %d,%d %d ", size, numItems, ptr);
+	
+	
+
+	if (DS::isGBAMPAvailable()) {
+	
+		
+		int bytes = FAT_fread((void *) ptr, size, numItems, (FAT_FILE *) handle);
+		if (!std_feof(handle)) {
+			return numItems;
+		} else {
+//			consolePrintf("Read past end of file: %d read out of %d\n", bytes / size, numItems);
+			return bytes / size;
+		}
+		return numItems;
+		
+/*		int item = 0;
+		u8* data = (u8 *) ptr;
+		while ((item < numItems) && (!FAT_feof((FAT_FILE *) handle))) {
+			
+
+			int bytes = 0;
+			while ((bytes < size) && (!FAT_feof((FAT_FILE *) handle))) {
+				*data++ = FAT_fgetc((FAT_FILE *) handle);
+				bytes++;
+			}
+			
+			item++;
+		
+		}
+		
+		return item;*/
+
+
+		int items = 0;
+	
+		//for (int r = 0; r < numItems; r++) {
+			if (!std_feof(handle)) {
+				
+
+				
+/*				for (int t = 0; t < size; t++) {
+					if (feof(handle)) eof = true;
+					*(((char *) (ptr)) + r * size + t) = getc(handle);
+				}*/
+				int left = size * numItems;;
+				int bytesRead = -1;
+				while ((left > 0) && (!FAT_feof((FAT_FILE *) handle))) {
+					int amount = left > 8192? 8192: left;
+//					do {
+						bytesRead = FAT_fread((void *) ptr, 1, amount, (FAT_FILE *) handle);
+	/*					if (bytesRead == 0) {
+							consolePrintf("Pos:%d items:%d num:%d amount:%d read:%d\n", ftell(handle), items, numItems, amount, bytesRead);
+							left++;
+							
+							int pos = ftell(handle);
+							
+							fseek(handle, 0, SEEK_SET);
+							int c = getc(handle);
+							fseek(handle, pos - 1024, SEEK_SET);
+							fread(ptr, 1024, 1, handle);
+							swiWaitForVBlank();
+							//while (true);
+						}*/
+					//} while (bytesRead == 0);
+					left -= bytesRead;
+					ptr = ((char *) (ptr)) + bytesRead;				
+				}
+				
+				items = numItems - (left / size);
+				
+			
+		
+				
+//				FAT_fread((void *) ptr, size, 1, ((int) (handle)) - 1);
+	//			ptr = ((char *) (ptr)) + size;
+				
+			}
+		//}
+		
+//		consolePrintf("...done %d \n", items)
+
+		return items;
+		
+	}
+	
+	if (handle->sramFile) {
+		int bytes = 0;
+		int result = 1;
+		//consolePrintf("fread size=", size * numItems);
+		for (int r = 0; (r < (s32) size * (s32) numItems) && (result > 0); r++) {
+			result = handle->sramFile->read((void *) ( ((char *) (ptr)) + r), 1);
+			bytes += result;
+			//consolePrintf("'%d',", ((char *) (ptr))[0]);
+		}
+		
+		handle->pos += bytes;
+		
+		return bytes / size;
+	}
+
+
+	if (handle->pos + size * numItems > handle->size) {
+		numItems = (handle->size - handle->pos) / size;
+		if (numItems < 0) numItems = 0;
+	}
+
+//	consolePrintf("read %d  ", size * numItems);
+
+	memcpy((void *) ptr, handle->data + handle->pos, size * numItems);
+
+	handle->pos += size * numItems;
+
+	
+	return numItems;
+}
+
+size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
+	if ((handle == stdin)) return 0;
+	
+	if ((handle == stderr) || (handle == stdout)) {
+//		consolePrintf((char *) ptr);
+		return size;
+	}
+
+	//consolePrintf("fwrite size=%d\n", size * numItems);
+
+	if (DS::isGBAMPAvailable()) {
+
+		FAT_fwrite(((char *) (ptr)), size, numItems, (FAT_FILE *) handle);
+		return numItems;
+		
+		int length = size * numItems;
+		int pos = 0;
+		
+		while (pos < length) {
+			int amount = length > 512? 512: length;
+			
+			FAT_fwrite(((char *) (ptr)) + pos, 1, amount, (FAT_FILE *) handle);
+			length -= amount;
+			pos += amount;		
+		}		
+	
+		return numItems;
+	}
+
+
+	if (handle->sramFile) {
+		handle->sramFile->write(ptr, size);
+		return size;
+	} else {
+		return 0;
+	}
+}
+
+void std_fprintf(FILE* handle, const char* fmt, ...) {
+	consolePrintf(fmt);
+}
+
+bool std_feof(FILE* handle) {
+//	consolePrintf("feof ");
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_feof((FAT_FILE *) handle);
+	}
+	
+	if (handle->sramFile) {
+		return handle->sramFile->eos();
+	}
+
+//	consolePrintf("feof %s", handle->pos >= handle->size? "true": "false");
+	return handle->pos >= handle->size;
+}
+
+void std_fflush(FILE* handle) {
+//	consolePrintf("fflush ");
+}
+
+char* std_fgets(char* str, int size, FILE* file) {
+//	consolePrintf("fgets file=%d ", file);
+	
+	if (DS::isGBAMPAvailable()) {
+		
+		char* s = str;
+		while ((*s++ = std_getc(file)) >= 32) {
+//			consolePrintf("%d ", *s);
+		}
+		*s = 0;
+		
+//		consolePrintf("Read:%s\n", str);
+	
+		return str;
+	}
+	
+	
+	if (file->sramFile) {
+		file->pos--;
+		int p = -1;
+		do {
+			file->pos++;
+			p++;
+			file->sramFile->read((char *) &str[p], 1);
+//			consolePrintf("%d,", str[p]);
+		} while ((str[p] >= 32) && (!feof(file)) && (p < size));
+		str[p + 1] = 0;
+		file->pos++;
+//		consolePrintf("Read:%s\n", str);
+		return str;
+	}
+	
+	return NULL;
+}
+
+long int std_ftell(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_ftell((FAT_FILE *) handle);
+	}
+
+	return handle->pos;
+}
+
+int std_fseek(FILE* handle, long int offset, int whence) {
+//	consolePrintf("fseek %d %d ", offset, whence);
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_fseek((FAT_FILE *) handle, offset, whence);
+	}
+
+
+	switch (whence) {
+		case SEEK_CUR: {
+			handle->pos += offset;
+			break;
+		}
+		
+		case SEEK_SET: {
+			handle->pos = offset;
+			break;
+		}
+		
+		case SEEK_END: {
+			handle->pos = handle->size + offset;
+			break;
+		}
+		
+		default: {
+			handle->pos = offset;
+			break;
+		}
+		
+	}
+	
+	return 0;
+}
+
+void std_clearerr(FILE* handle) {
+//	consolePrintf("clearerr ");
+}
+
+int std_getc(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		char c;
+		FAT_fread(&c, 1, 1, (FAT_FILE *) handle);
+		
+		return c;
+	}
+
+//	consolePrintf("fgetc ");
+	return 0;				// Not supported yet
+}
+
+char* std_getcwd(char* dir, int dunno) {
+//	consolePrintf("getcwd ");
+	dir[0] = '\0';
+	return dir;			// Not supported yet
+}
+
+void std_cwd(char* dir) {
+	char buffer[128];
+	strcpy(buffer, dir);
+	char* realName = buffer;
+
+	if (DS::isGBAMPAvailable()) {
+		if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) {
+			realName += 4;
+		}
+	
+	//	consolePrintf("Real cwd:%d\n", realName);
+		
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+	//	consolePrintf("Real cwd:%d\n", realName);
+		FAT_chdir(realName);
+	} else {
+		if ((strlen(dir) >= 4) && (dir[0] == 'd') && (dir[1] == 's') && (dir[2] == ':') && (dir[3] == '/')) {
+			realName += 4;
+		}
+
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+		strcpy(currentDir, realName);
+		if (*(currentDir + strlen(currentDir) - 1) == '/') {
+			*(currentDir + strlen(currentDir) - 1) = '\0';
+		}
+		consolePrintf("CWD: %s\n", currentDir);
+	}	
+}
+
+int std_ferror(FILE* handle) {
+	return 0;
+}
+
+} // namespace DS
+
+// These functions are added to AbstractFileSystemNode and are therefore outside
+// the DS namespace.
+
+AbstractFilesystemNode *AbstractFilesystemNode::getCurrentDirectory() {
+//	consolePrintf("New node");
+        
+	if (DS::isGBAMPAvailable()) {
+		return new DS::GBAMPFileSystemNode();
+	} else {
+		return new DS::DSFileSystemNode();
+	}
+}
+
+AbstractFilesystemNode* AbstractFilesystemNode::getNodeForPath(const String& path) {
+	if (DS::isGBAMPAvailable()) {
+		return new DS::GBAMPFileSystemNode(path);
+	} else {
+		return new DS::DSFileSystemNode(path);
+	}
+}
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+
+#include "stdafx.h"
+#include "str.h"
+#include "fs.h"
+#include "common/util.h"
+#include <NDS/ARM9/console.h> //basic print funcionality
+#include "ds-fs.h"
+#include "dsmain.h"
+#include "gba_nds_fat.h"
+
+namespace DS {
+
+//////////////////////////////////////////////////////////////
+// DSFileSystemNode - Flash ROM file system using Zip files
+//////////////////////////////////////////////////////////////
+
+ZipFile*   	DSFileSystemNode::_zipFile = NULL;
+char		currentDir[128];
+
+DSFileSystemNode::DSFileSystemNode() {
+	_displayName = "ds:/";
+	_path = "ds:/";
+	_isValid = true;
+	_isDirectory = true;
+	_path = "ds:/";
+
+/*	if (!_archive) {
+		_archive = (GBFS_FILE *) find_first_gbfs_file(scummdata);
+		if (!_archive) consolePrintf("No GBFS archive found!\n");
+	}*/
+	
+	if (!_zipFile) {
+		_zipFile = new ZipFile();
+	}
+}
+
+DSFileSystemNode::DSFileSystemNode(const String& path) {
+//	consolePrintf("--%s ",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	
+	
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if (path[r] == '\\') {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+	
+	_displayName = String(disp);
+	_path = path;
+//	_isValid = true;
+//	_isDirectory = false;
+
+
+
+	if (!strncmp(pathStr, "ds:/", 4)) {
+		pathStr += 4;
+	}
+	
+
+	if (*pathStr == '\0') {
+		_isValid = true;
+		_isDirectory = true;
+		return;
+	}
+	
+	_zipFile->setAllFilesVisible(true);
+	if (_zipFile->findFile(pathStr)) {
+		_isValid = true;
+		_isDirectory = _zipFile->isDirectory();
+	} else {
+		_isValid = false;
+		_isDirectory = false;
+	}
+	_zipFile->setAllFilesVisible(false);
+	
+//	consolePrintf("%s - Found: %d, Dir: %d\n", pathStr, _isValid, _isDirectory);
+}
+
+DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) {
+//	consolePrintf("--%s ",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if (path[r] == '\\') {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+	
+	_displayName = String(disp);
+	_path = path;
+	_isValid = true;
+	_isDirectory = isDir;
+	
+//	consolePrintf("Found: %d, Dir: %d\n", _isValid, _isDirectory);
+}
+
+DSFileSystemNode::DSFileSystemNode(const DSFileSystemNode* node) {
+
+}
+
+AbstractFilesystemNode* DSFileSystemNode::parent() const {
+//	consolePrintf("parent\n");
+	DSFileSystemNode *p;
+
+	if (_path != "ds:/") {  
+		char *path = (char *) _path.c_str();
+		int lastSlash = 4;
+		
+		for (int r = 4; r < (int) strlen((char *) path); r++) {
+			if (path[r] == '\\') {
+				lastSlash = r;
+			}
+		}
+
+		p = new DSFileSystemNode(String(path, lastSlash));
+		((DSFileSystemNode *) (p))->_isDirectory = true;
+	} else {
+		p = new DSFileSystemNode();
+	}
+
+	return p;
+
+}
+
+
+AbstractFilesystemNode *DSFileSystemNode::child(const Common::String& name) const {
+	if (_path.lastChar() == '\\') {
+		return new DSFileSystemNode(_path + name);
+	} else {
+		return new DSFileSystemNode(_path + "\\" + name);
+	}
+	
+	return NULL;
+}
+
+
+bool DSFileSystemNode::listDir(AbstractFSList &dirList, ListMode mode) const {
+//	consolePrintf("Listdir\n");
+
+	
+//	consolePrintf("Directory\n");
+
+	
+	char temp[128];
+	strcpy(temp, _path.c_str());
+
+//	consolePrintf("This dir: %s\n", temp);
+
+	if ((temp[0] == 'd') && (temp[1] == 's') && (temp[2] == ':') && (temp[3] == '/')) {
+		if (strlen(temp) != 4) {
+			_zipFile->changeDirectory(&temp[4]);
+		} else {
+			_zipFile->changeToRoot();
+			
+/*			// This is the root dir, so add the RAM folder
+			DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/ram");
+			dsfsn->_isDirectory = true;
+			dirList->push_back(wrap(dsfsn));*/
+		}
+	} else {
+		_zipFile->changeDirectory(temp);
+	}
+	
+	
+	
+	if (_zipFile->restartFile()) {
+		do {
+			char name[128];	
+			_zipFile->getFileName(name);
+	
+//			consolePrintf("file: %s\n", name);
+			if ( (_zipFile->isDirectory() && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)) ) 
+				|| (!_zipFile->isDirectory() && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll)) ) ) 
+			{
+				DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + String(name), _zipFile->isDirectory());
+				dsfsn->_isDirectory = _zipFile->isDirectory();
+				dirList.push_back((dsfsn));
+			}
+			
+		} while (_zipFile->skipFile());
+	}
+
+	return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// GBAMPFileSystemNode - File system using GBA Movie Player and CF card
+/////////////////////////////////////////////////////////////////////////
+
+GBAMPFileSystemNode::GBAMPFileSystemNode() {
+	_displayName = "mp:/";
+	_path = "mp:/";
+	_isValid = true;
+	_isDirectory = true;
+	_path = "mp:/";
+}
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) {
+//	consolePrintf("'%s'",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if ((path[r] == '\\') || (path[r] == '/')) {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+
+	char check[128];
+	int success;
+	
+	memset(check, 0, 128);
+	if (strlen(pathStr) > 3) {
+		strcpy(check, pathStr + 3);
+		if (check[strlen(check) - 1] == '/') {
+			check[strlen(check) - 1] = 0;
+		}
+		success = FAT_FileExists(check);
+	} else {
+		success = FT_DIR;
+	}
+//	consolePrintf("Path: %s  (%d)\n", check, success);
+	
+	_displayName = String(disp);
+	_path = path;
+	_isValid = success == FT_FILE;
+	_isDirectory = success == FT_DIR;
+}
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) {
+//	consolePrintf("'%s'",path.c_str());
+	
+	char disp[128];
+	char* pathStr = (char *) path.c_str();
+	int lastSlash = 3;
+	for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
+		if ((path[r] == '\\') || (path[r] == '/')) {
+			lastSlash = r;
+		}
+	}
+	
+	strcpy(disp, pathStr + lastSlash + 1);
+
+	_displayName = String(disp);
+	_path = path;
+	_isValid = true;
+	_isDirectory = isDirectory;
+}
+
+
+GBAMPFileSystemNode::GBAMPFileSystemNode(const GBAMPFileSystemNode* node) {
+
+}
+
+
+AbstractFilesystemNode* GBAMPFileSystemNode::parent() const {
+//	consolePrintf("parent\n");
+	GBAMPFileSystemNode *p;
+
+	if (_path != "mp:/") {  
+		char *path = (char *) _path.c_str();
+		int lastSlash = 4;
+		
+		for (int r = 4; r < (int) strlen((char *) path); r++) {
+			if (path[r] == '/') {
+				lastSlash = r;
+			}
+		}
+
+		p = new GBAMPFileSystemNode(String(path, lastSlash));
+		p->_isDirectory = true;
+	} else {
+		p = new GBAMPFileSystemNode();
+	}
+
+	return p;
+
+}
+
+AbstractFilesystemNode *GBAMPFileSystemNode::child(const Common::String& name) const {
+	if (_path.lastChar() == '\\') {
+		return new DSFileSystemNode(_path + name);
+	} else {
+		return new DSFileSystemNode(_path + "\\" + name);
+	}
+	
+	return NULL;
+}
+
+bool GBAMPFileSystemNode::listDir(AbstractFSList& dirList, ListMode mode) const {
+//	consolePrintf("Listdir\n");
+
+	enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
+	
+	char temp[128], fname[128], *path, *pathTemp;
+	strcpy(temp, _path.c_str());
+	
+	path = temp + 3;
+	
+	pathTemp = path;
+	while (*pathTemp) {
+		if (*pathTemp == '\\') {
+			*pathTemp = '/';
+		}
+		pathTemp++;
+	}
+
+
+//	consolePrintf("This dir: %s\n", path);
+	FAT_chdir(path);
+	
+	int entryType = FAT_FindFirstFile(fname);
+	
+	while (entryType != TYPE_NO_MORE) {
+	
+		if ( ((entryType == TYPE_DIR) && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)))
+		||   ((entryType == TYPE_FILE) && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll))) ) {
+			GBAMPFileSystemNode* dsfsn;
+			
+			if (strcmp(fname, ".") && strcmp(fname, "..")) {
+				
+				if (!strcmp(path, "/")) {
+					dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String(fname), entryType == TYPE_DIR);
+				} else {
+					dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String("/") + String(fname), entryType == TYPE_DIR);
+				}
+				
+//				dsfsn->_isDirectory = entryType == DIR;
+				dirList.push_back((dsfsn));
+			}
+		
+		
+		} else {
+//			consolePrintf("Skipping %s\n", fname);
+		}
+		
+		entryType = FAT_FindNextFile(fname);
+	}
+	
+//	consolePrintf("No more");
+	
+	FAT_chdir("/");
+
+	return true;
+}
+
+
+// Stdio replacements
+#define MAX_FILE_HANDLES 32
+
+bool inited = false;
+DS::fileHandle handle[MAX_FILE_HANDLES];
+
+FILE* std_fopen(const char* name, const char* mode) {
+
+	
+
+	if (!inited) {
+		for (int r = 0; r < MAX_FILE_HANDLES; r++) {
+			handle[r].used = false;
+		}
+		inited = true;
+		currentDir[0] = '\0';
+	}
+
+
+	
+	
+	char* realName = (char *) name;
+	
+	// Remove file system prefix
+	if ((name[0] == 'd') && (name[1] == 's') && (name[2] == ':') && (name[3] == '/')) {
+		realName += 4;
+	}
+
+	if ((name[0] == 'm') && (name[1] == 'p') && (name[2] == ':') && (name[3] == '/')) {
+		realName += 4;
+	}
+
+//	consolePrintf("Open file:");
+//	consolePrintf("'%s', [%s]", realName, mode);
+
+
+	if (DS::isGBAMPAvailable()) {
+		FAT_chdir("/");
+		
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+		FAT_FILE* result = FAT_fopen(realName, mode);
+		
+		if (result == 0) {
+//			consolePrintf("Error code %d\n", result);
+			//consolePrintf("Opening file %s\n", realName);
+		} else {
+//			consolePrintf("Opened file %d\n", result);
+		}
+//		MT_memoryReport();
+		
+		return (fileHandle *) result;
+	}
+
+	
+	// Fail to open file for writing.  It's in ROM!
+
+	// Allocate a file handle
+	int r = 0;
+	while (handle[r].used) r++;
+	
+	if (strchr(mode, 'w')) {
+//		consolePrintf("Writing %s\n", realName);
+		handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true);
+	} else {
+//		consolePrintf("Reading %s\n", realName);
+		handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false);
+	}
+
+	
+	if (handle[r].sramFile) {
+		handle[r].used = true;
+		handle[r].pos = 0;
+		handle[r].data = NULL;
+		handle[r].size = handle[r].sramFile->getSize();
+//		consolePrintf("Found it");
+		return &handle[r];
+	} 
+
+//	consolePrintf("Not in SRAM!");
+
+	char* data;
+	
+	ZipFile* zip = DSFileSystemNode::getZip();
+	if (!zip) {
+//		consolePrintf("No zip yet!");
+		return NULL;
+	}
+	
+	// Grab the data if it exists
+	
+	zip->setAllFilesVisible(true);
+	
+	if (currentDir[0] != 0) {
+		char nameWithPath[128];
+		sprintf(nameWithPath, "%s\%s", currentDir, realName);
+		strcpy(realName, nameWithPath);
+	}
+
+//	consolePrintf("fopen(%s, %s)\n", realName, name);
+		
+	if (zip->findFile(realName)) {
+		data = zip->getFile();
+		zip->setAllFilesVisible(false);
+		
+		// Allocate a file handle
+		int r = 0;
+		while (handle[r].used) r++;
+	
+	
+		handle[r].used = true;
+		handle[r].pos = 0;
+		handle[r].data = data;
+		handle[r].size = zip->getFileSize();
+
+//		consolePrintf("Opened file %d: %s (%s)   ", r, realName, name);
+		return &handle[r];
+	} else {
+		zip->setAllFilesVisible(false);
+//		consolePrintf("Not found: %s (%s)  ", realName, name);
+		return NULL;
+	}
+}
+void std_fclose(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		FAT_fclose((FAT_FILE *) handle);
+		return;
+	}
+
+	handle->used = false;
+	if (handle->sramFile) {
+		delete handle->sramFile;
+		handle->sramFile = NULL;
+	}
+}
+
+size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) {
+
+//	consolePrintf("fread %d,%d %d ", size, numItems, ptr);
+	
+	
+
+	if (DS::isGBAMPAvailable()) {
+	
+		
+		int bytes = FAT_fread((void *) ptr, size, numItems, (FAT_FILE *) handle);
+		if (!std_feof(handle)) {
+			return numItems;
+		} else {
+//			consolePrintf("Read past end of file: %d read out of %d\n", bytes / size, numItems);
+			return bytes / size;
+		}
+		return numItems;
+		
+/*		int item = 0;
+		u8* data = (u8 *) ptr;
+		while ((item < numItems) && (!FAT_feof((FAT_FILE *) handle))) {
+			
+
+			int bytes = 0;
+			while ((bytes < size) && (!FAT_feof((FAT_FILE *) handle))) {
+				*data++ = FAT_fgetc((FAT_FILE *) handle);
+				bytes++;
+			}
+			
+			item++;
+		
+		}
+		
+		return item;*/
+
+
+		int items = 0;
+	
+		//for (int r = 0; r < numItems; r++) {
+			if (!std_feof(handle)) {
+				
+
+				
+/*				for (int t = 0; t < size; t++) {
+					if (feof(handle)) eof = true;
+					*(((char *) (ptr)) + r * size + t) = getc(handle);
+				}*/
+				int left = size * numItems;;
+				int bytesRead = -1;
+				while ((left > 0) && (!FAT_feof((FAT_FILE *) handle))) {
+					int amount = left > 8192? 8192: left;
+//					do {
+						bytesRead = FAT_fread((void *) ptr, 1, amount, (FAT_FILE *) handle);
+	/*					if (bytesRead == 0) {
+							consolePrintf("Pos:%d items:%d num:%d amount:%d read:%d\n", ftell(handle), items, numItems, amount, bytesRead);
+							left++;
+							
+							int pos = ftell(handle);
+							
+							fseek(handle, 0, SEEK_SET);
+							int c = getc(handle);
+							fseek(handle, pos - 1024, SEEK_SET);
+							fread(ptr, 1024, 1, handle);
+							swiWaitForVBlank();
+							//while (true);
+						}*/
+					//} while (bytesRead == 0);
+					left -= bytesRead;
+					ptr = ((char *) (ptr)) + bytesRead;				
+				}
+				
+				items = numItems - (left / size);
+				
+			
+		
+				
+//				FAT_fread((void *) ptr, size, 1, ((int) (handle)) - 1);
+	//			ptr = ((char *) (ptr)) + size;
+				
+			}
+		//}
+		
+//		consolePrintf("...done %d \n", items)
+
+		return items;
+		
+	}
+	
+	if (handle->sramFile) {
+		int bytes = 0;
+		int result = 1;
+		//consolePrintf("fread size=", size * numItems);
+		for (int r = 0; (r < (s32) size * (s32) numItems) && (result > 0); r++) {
+			result = handle->sramFile->read((void *) ( ((char *) (ptr)) + r), 1);
+			bytes += result;
+			//consolePrintf("'%d',", ((char *) (ptr))[0]);
+		}
+		
+		handle->pos += bytes;
+		
+		return bytes / size;
+	}
+
+
+	if (handle->pos + size * numItems > handle->size) {
+		numItems = (handle->size - handle->pos) / size;
+		if (numItems < 0) numItems = 0;
+	}
+
+//	consolePrintf("read %d  ", size * numItems);
+
+	memcpy((void *) ptr, handle->data + handle->pos, size * numItems);
+
+	handle->pos += size * numItems;
+
+	
+	return numItems;
+}
+
+size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
+	if ((handle == stdin)) return 0;
+	
+	if ((handle == stderr) || (handle == stdout)) {
+//		consolePrintf((char *) ptr);
+		return size;
+	}
+
+	//consolePrintf("fwrite size=%d\n", size * numItems);
+
+	if (DS::isGBAMPAvailable()) {
+
+		FAT_fwrite(((char *) (ptr)), size, numItems, (FAT_FILE *) handle);
+		return numItems;
+		
+		int length = size * numItems;
+		int pos = 0;
+		
+		while (pos < length) {
+			int amount = length > 512? 512: length;
+			
+			FAT_fwrite(((char *) (ptr)) + pos, 1, amount, (FAT_FILE *) handle);
+			length -= amount;
+			pos += amount;		
+		}		
+	
+		return numItems;
+	}
+
+
+	if (handle->sramFile) {
+		handle->sramFile->write(ptr, size);
+		return size;
+	} else {
+		return 0;
+	}
+}
+
+void std_fprintf(FILE* handle, const char* fmt, ...) {
+	consolePrintf(fmt);
+}
+
+bool std_feof(FILE* handle) {
+//	consolePrintf("feof ");
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_feof((FAT_FILE *) handle);
+	}
+	
+	if (handle->sramFile) {
+		return handle->sramFile->eos();
+	}
+
+//	consolePrintf("feof %s", handle->pos >= handle->size? "true": "false");
+	return handle->pos >= handle->size;
+}
+
+void std_fflush(FILE* handle) {
+//	consolePrintf("fflush ");
+}
+
+char* std_fgets(char* str, int size, FILE* file) {
+//	consolePrintf("fgets file=%d ", file);
+	
+	if (DS::isGBAMPAvailable()) {
+		
+		char* s = str;
+		while ((*s++ = std_getc(file)) >= 32) {
+//			consolePrintf("%d ", *s);
+		}
+		*s = 0;
+		
+//		consolePrintf("Read:%s\n", str);
+	
+		return str;
+	}
+	
+	
+	if (file->sramFile) {
+		file->pos--;
+		int p = -1;
+		do {
+			file->pos++;
+			p++;
+			file->sramFile->read((char *) &str[p], 1);
+//			consolePrintf("%d,", str[p]);
+		} while ((str[p] >= 32) && (!feof(file)) && (p < size));
+		str[p + 1] = 0;
+		file->pos++;
+//		consolePrintf("Read:%s\n", str);
+		return str;
+	}
+	
+	return NULL;
+}
+
+long int std_ftell(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_ftell((FAT_FILE *) handle);
+	}
+
+	return handle->pos;
+}
+
+int std_fseek(FILE* handle, long int offset, int whence) {
+//	consolePrintf("fseek %d %d ", offset, whence);
+
+	if (DS::isGBAMPAvailable()) {
+		return FAT_fseek((FAT_FILE *) handle, offset, whence);
+	}
+
+
+	switch (whence) {
+		case SEEK_CUR: {
+			handle->pos += offset;
+			break;
+		}
+		
+		case SEEK_SET: {
+			handle->pos = offset;
+			break;
+		}
+		
+		case SEEK_END: {
+			handle->pos = handle->size + offset;
+			break;
+		}
+		
+		default: {
+			handle->pos = offset;
+			break;
+		}
+		
+	}
+	
+	return 0;
+}
+
+void std_clearerr(FILE* handle) {
+//	consolePrintf("clearerr ");
+}
+
+int std_getc(FILE* handle) {
+
+	if (DS::isGBAMPAvailable()) {
+		char c;
+		FAT_fread(&c, 1, 1, (FAT_FILE *) handle);
+		
+		return c;
+	}
+
+//	consolePrintf("fgetc ");
+	return 0;				// Not supported yet
+}
+
+char* std_getcwd(char* dir, int dunno) {
+//	consolePrintf("getcwd ");
+	dir[0] = '\0';
+	return dir;			// Not supported yet
+}
+
+void std_cwd(char* dir) {
+	char buffer[128];
+	strcpy(buffer, dir);
+	char* realName = buffer;
+
+	if (DS::isGBAMPAvailable()) {
+		if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) {
+			realName += 4;
+		}
+	
+	//	consolePrintf("Real cwd:%d\n", realName);
+		
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+	//	consolePrintf("Real cwd:%d\n", realName);
+		FAT_chdir(realName);
+	} else {
+		if ((strlen(dir) >= 4) && (dir[0] == 'd') && (dir[1] == 's') && (dir[2] == ':') && (dir[3] == '/')) {
+			realName += 4;
+		}
+
+		char* p = realName;
+		while (*p) {
+			if (*p == '\\') *p = '/';
+			p++;
+		}
+		
+		strcpy(currentDir, realName);
+		if (*(currentDir + strlen(currentDir) - 1) == '/') {
+			*(currentDir + strlen(currentDir) - 1) = '\0';
+		}
+		consolePrintf("CWD: %s\n", currentDir);
+	}	
+}
+
+int std_ferror(FILE* handle) {
+	return 0;
+}
+
+} // namespace DS
+
+// These functions are added to AbstractFileSystemNode and are therefore outside
+// the DS namespace.
+
+AbstractFilesystemNode *AbstractFilesystemNode::getCurrentDirectory() {
+//	consolePrintf("New node");
+        
+	if (DS::isGBAMPAvailable()) {
+		return new DS::GBAMPFileSystemNode();
+	} else {
+		return new DS::DSFileSystemNode();
+	}
+}
+
+AbstractFilesystemNode* AbstractFilesystemNode::getNodeForPath(const String& path) {
+	if (DS::isGBAMPAvailable()) {
+		return new DS::GBAMPFileSystemNode(path);
+	} else {
+		return new DS::DSFileSystemNode(path);
+	}
+}
\ No newline at end of file


Property changes on: scummvm/trunk/backends/fs/ds/ds-fs.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/fs/ds/ds-fs.h
===================================================================
--- scummvm/trunk/backends/fs/ds/ds-fs.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/fs/ds/ds-fs.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,356 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DS_FS_H
+#define _DS_FS_H
+
+
+#include "stdafx.h"
+#include "common/array.h"
+#include "common/str.h"
+
+//#include <NDS/ARM9/console.h>
+#include "fs.h"
+#include "zipreader.h"
+#include "ramsave.h"
+#include "scummconsole.h"
+#include "gba_nds_fat.h"
+#include "backends/fs/abstract-fs.h"
+//#include "backends/fs/fs.h"
+
+// Fix name clash with FOTAQ engine, cutaway.h
+#undef MAX_FILENAME_LENGTH
+// This class is used when a Flash cart is in use
+
+namespace DS {
+
+class DSFileSystemNode : public AbstractFilesystemNode {
+protected:
+	static ZipFile* _zipFile;
+
+	typedef class Common::String String;
+
+	String _displayName;
+	bool _isDirectory;
+	bool _isValid;
+	String _path;
+	int _refCountVal;
+	
+public:
+	DSFileSystemNode();
+	DSFileSystemNode(const String &path);
+	DSFileSystemNode(const DSFileSystemNode *node);
+	DSFileSystemNode(const String& path, bool isDir);
+	
+	virtual String displayName() const {  return _displayName; }
+	virtual bool isValid() const { return _isValid; }
+	virtual bool isDirectory() const { return _isDirectory; }
+	virtual String path() const { return _path; }
+	
+	virtual bool listDir(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly) const;
+	virtual AbstractFilesystemNode *parent() const;
+	virtual AbstractFilesystemNode *clone() const { return new DSFileSystemNode(this); }
+	virtual AbstractFilesystemNode *child(const Common::String& name) const;
+	static ZipFile* getZip() { return _zipFile; }
+};
+
+
+// This class is used when the GBAMP (GBA Movie Player) is used with a CompactFlash card
+
+class GBAMPFileSystemNode : public AbstractFilesystemNode {
+protected:
+	typedef class Common::String String;
+
+	String _displayName;
+	bool _isDirectory;
+	bool _isValid;
+	String _path;
+	
+	int _refCountVal;
+	
+public:
+	GBAMPFileSystemNode();
+	GBAMPFileSystemNode(const String &path);
+	GBAMPFileSystemNode(const String &path, bool isDirectory);
+	GBAMPFileSystemNode(const GBAMPFileSystemNode *node);
+
+	virtual String displayName() const {  return _displayName; }
+	virtual bool isValid() const { return _isValid; }
+	virtual bool isDirectory() const { return _isDirectory; }
+	virtual String path() const { return _path; }
+	virtual bool listDir(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly) const;
+	virtual AbstractFilesystemNode *parent() const;
+	virtual AbstractFilesystemNode *clone() const { return new GBAMPFileSystemNode(this); }
+	virtual AbstractFilesystemNode *child(const Common::String& name) const;
+	
+};
+
+
+// File reading
+
+
+struct fileHandle {
+	int pos;
+	bool used;
+	char* data;
+	int size;
+	
+	DSSaveFile* sramFile;
+};
+
+// These functions replease the standard library functions of the same name.
+// As this header is included after the standard one, I have the chance to #define
+// all of these to my own code.
+//
+// A #define is the only way, as redefinig the functions would cause linker errors.
+
+// These functions need to be #undef'ed, as their definition is done with #includes
+#undef feof
+#undef stderr
+#undef stdout
+#undef stdin
+#undef clearerr
+#undef getc
+#undef ferror
+
+#define stdout ((DS::fileHandle*) -1)
+#define stderr ((DS::fileHandle*) -2)
+#define stdin ((DS::fileHandle*) -3)
+
+#define FILE DS::fileHandle
+//#define size_t int
+
+//#define FAT_chdir FAT_CWD
+
+FILE* 	std_fopen(const char* name, const char* mode);
+void 	std_fclose(FILE* handle);
+size_t 	std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle);
+size_t 	std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle);
+void 	std_fprintf(FILE* handle, const char* fmt, ...);
+bool 	std_feof(FILE* handle);
+void 	std_fflush(FILE* handle);
+char* 	std_fgets(char* str, int size, FILE* file);
+long int std_ftell(FILE* handle);
+int 	std_fseek(FILE* handle, long int offset, int whence);
+void 	std_clearerr(FILE* handle);
+int 	std_getc(FILE* handle);
+char* 	std_getcwd(char* dir, int dunno);
+void 	std_cwd(char* dir);
+int 	std_ferror(FILE* handle);
+
+// Only functions used in the ScummVM source have been defined here!
+#define fopen(name, mode) 					DS::std_fopen(name, mode)
+#define fclose(handle) 						DS::std_fclose(handle)
+#define fread(ptr, size, items, file)		DS::std_fread(ptr, size, items, file)
+#define fwrite(ptr, size, items, file)		DS::std_fwrite(ptr, size, items, file)
+#define feof(handle)						DS::std_feof(handle)
+//#define fprintf(file, fmt, ...)				DS::fprintf(file, fmt, ##__VA_ARGS__)
+#define fprintf(file, fmt, ...)				{ char str[128]; sprintf(str, fmt, ##__VA_ARGS__); DS::std_fwrite(str, strlen(str), 1, file); }
+#define printf(fmt, ...)					consolePrintf(fmt, ##__VA_ARGS__)
+#define fflush(file)						DS::std_fflush(file)
+#define fgets(str, size, file)				DS::std_fgets(str, size, file)
+#define ftell(handle)						DS::std_ftell(handle)
+#define fseek(handle, offset, whence)		DS::std_fseek(handle, offset, whence)
+#define clearerr(handle)					DS::std_clearerr(handle)
+#define getc(handle)						DS::std_getc(handle)
+#define getcwd(dir, dunno)					DS::std_getcwd(dir, dunno)
+#define ferror(handle)						DS::std_ferror(handle)
+
+
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DS_FS_H
+#define _DS_FS_H
+
+
+#include "stdafx.h"
+#include "common/array.h"
+#include "common/str.h"
+
+//#include <NDS/ARM9/console.h>
+#include "fs.h"
+#include "zipreader.h"
+#include "ramsave.h"
+#include "scummconsole.h"
+#include "gba_nds_fat.h"
+#include "backends/fs/abstract-fs.h"
+//#include "backends/fs/fs.h"
+
+// Fix name clash with FOTAQ engine, cutaway.h
+#undef MAX_FILENAME_LENGTH
+// This class is used when a Flash cart is in use
+
+namespace DS {
+
+class DSFileSystemNode : public AbstractFilesystemNode {
+protected:
+	static ZipFile* _zipFile;
+
+	typedef class Common::String String;
+
+	String _displayName;
+	bool _isDirectory;
+	bool _isValid;
+	String _path;
+	int _refCountVal;
+	
+public:
+	DSFileSystemNode();
+	DSFileSystemNode(const String &path);
+	DSFileSystemNode(const DSFileSystemNode *node);
+	DSFileSystemNode(const String& path, bool isDir);
+	
+	virtual String displayName() const {  return _displayName; }
+	virtual bool isValid() const { return _isValid; }
+	virtual bool isDirectory() const { return _isDirectory; }
+	virtual String path() const { return _path; }
+	
+	virtual bool listDir(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly) const;
+	virtual AbstractFilesystemNode *parent() const;
+	virtual AbstractFilesystemNode *clone() const { return new DSFileSystemNode(this); }
+	virtual AbstractFilesystemNode *child(const Common::String& name) const;
+	static ZipFile* getZip() { return _zipFile; }
+};
+
+
+// This class is used when the GBAMP (GBA Movie Player) is used with a CompactFlash card
+
+class GBAMPFileSystemNode : public AbstractFilesystemNode {
+protected:
+	typedef class Common::String String;
+
+	String _displayName;
+	bool _isDirectory;
+	bool _isValid;
+	String _path;
+	
+	int _refCountVal;
+	
+public:
+	GBAMPFileSystemNode();
+	GBAMPFileSystemNode(const String &path);
+	GBAMPFileSystemNode(const String &path, bool isDirectory);
+	GBAMPFileSystemNode(const GBAMPFileSystemNode *node);
+
+	virtual String displayName() const {  return _displayName; }
+	virtual bool isValid() const { return _isValid; }
+	virtual bool isDirectory() const { return _isDirectory; }
+	virtual String path() const { return _path; }
+	virtual bool listDir(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly) const;
+	virtual AbstractFilesystemNode *parent() const;
+	virtual AbstractFilesystemNode *clone() const { return new GBAMPFileSystemNode(this); }
+	virtual AbstractFilesystemNode *child(const Common::String& name) const;
+	
+};
+
+
+// File reading
+
+
+struct fileHandle {
+	int pos;
+	bool used;
+	char* data;
+	int size;
+	
+	DSSaveFile* sramFile;
+};
+
+// These functions replease the standard library functions of the same name.
+// As this header is included after the standard one, I have the chance to #define
+// all of these to my own code.
+//
+// A #define is the only way, as redefinig the functions would cause linker errors.
+
+// These functions need to be #undef'ed, as their definition is done with #includes
+#undef feof
+#undef stderr
+#undef stdout
+#undef stdin
+#undef clearerr
+#undef getc
+#undef ferror
+
+#define stdout ((DS::fileHandle*) -1)
+#define stderr ((DS::fileHandle*) -2)
+#define stdin ((DS::fileHandle*) -3)
+
+#define FILE DS::fileHandle
+//#define size_t int
+
+//#define FAT_chdir FAT_CWD
+
+FILE* 	std_fopen(const char* name, const char* mode);
+void 	std_fclose(FILE* handle);
+size_t 	std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle);
+size_t 	std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle);
+void 	std_fprintf(FILE* handle, const char* fmt, ...);
+bool 	std_feof(FILE* handle);
+void 	std_fflush(FILE* handle);
+char* 	std_fgets(char* str, int size, FILE* file);
+long int std_ftell(FILE* handle);
+int 	std_fseek(FILE* handle, long int offset, int whence);
+void 	std_clearerr(FILE* handle);
+int 	std_getc(FILE* handle);
+char* 	std_getcwd(char* dir, int dunno);
+void 	std_cwd(char* dir);
+int 	std_ferror(FILE* handle);
+
+// Only functions used in the ScummVM source have been defined here!
+#define fopen(name, mode) 					DS::std_fopen(name, mode)
+#define fclose(handle) 						DS::std_fclose(handle)
+#define fread(ptr, size, items, file)		DS::std_fread(ptr, size, items, file)
+#define fwrite(ptr, size, items, file)		DS::std_fwrite(ptr, size, items, file)
+#define feof(handle)						DS::std_feof(handle)
+//#define fprintf(file, fmt, ...)				DS::fprintf(file, fmt, ##__VA_ARGS__)
+#define fprintf(file, fmt, ...)				{ char str[128]; sprintf(str, fmt, ##__VA_ARGS__); DS::std_fwrite(str, strlen(str), 1, file); }
+#define printf(fmt, ...)					consolePrintf(fmt, ##__VA_ARGS__)
+#define fflush(file)						DS::std_fflush(file)
+#define fgets(str, size, file)				DS::std_fgets(str, size, file)
+#define ftell(handle)						DS::std_ftell(handle)
+#define fseek(handle, offset, whence)		DS::std_fseek(handle, offset, whence)
+#define clearerr(handle)					DS::std_clearerr(handle)
+#define getc(handle)						DS::std_getc(handle)
+#define getcwd(dir, dunno)					DS::std_getcwd(dir, dunno)
+#define ferror(handle)						DS::std_ferror(handle)
+
+
+}
+
+#endif


Property changes on: scummvm/trunk/backends/fs/ds/ds-fs.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm7/Makefile
===================================================================
--- scummvm/trunk/backends/platform/ds/arm7/Makefile	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm7/Makefile	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,436 @@
+#---------------------------------------------------------------------------------
+.SUFFIXES:
+#---------------------------------------------------------------------------------
+ 
+#---------------------------------------------------------------------------------
+# TARGET is the name of the output, if this ends with _mb generates a multiboot image
+# BUILD is the directory where object files & intermediate files will be placed
+# SOURCES is a list of directories containing source code
+# INCLUDES is a list of directories containing extra header files
+#---------------------------------------------------------------------------------
+TARGET	:=	arm7
+BUILD		:=	build
+SOURCES	:=	gfx source data  
+INCLUDES	:=	include build
+ 
+#---------------------------------------------------------------------------------
+# options for code generation
+#---------------------------------------------------------------------------------
+ARCH	:=	-mthumb-interwork
+
+# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD
+# *insists* it has a FPU or VFP, and it won't take no for an answer!
+CFLAGS	:=	-g -Wall -O2\
+ 		-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
+		-ffast-math \
+		$(ARCH)
+
+CFLAGS	+=	$(INCLUDE) -DARM7
+
+CXXFLAGS	:=	$(CFLAGS) -fno-exceptions -fno-rtti
+ASFLAGS	:=	-g $(ARCH)
+LDFLAGS	:=	-g $(ARCH) -mno-fpu
+
+#---------------------------------------------------------------------------------
+# path to tools - this can be deleted if you set the path in windows
+#---------------------------------------------------------------------------------
+# export PATH		:=	/d/dev/ds/devkitARM_r11/bin:/bin
+ 
+#---------------------------------------------------------------------------------
+# PATH to ndslib - just make a system variable called NDSLIBPATH and be done with it
+#---------------------------------------------------------------------------------
+# NDSLIBPATH	:=	/d/dev/ds/ndslib/
+ 
+#---------------------------------------------------------------------------------
+# the prefix on the compiler executables
+#---------------------------------------------------------------------------------
+PREFIX			:=	arm-eabi-
+#---------------------------------------------------------------------------------
+# any extra libraries we wish to link with the project
+#---------------------------------------------------------------------------------
+LIBS	:= -lnds7
+ 
+ 
+#---------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# include and lib
+#---------------------------------------------------------------------------------
+LIBDIRS	:=	$(DEVKITPRO)/libnds
+ 
+ 
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+ 
+export OUTPUT	:=	$(CURDIR)/$(TARGET)
+ 
+export VPATH	:=	$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
+ 
+export CC		:=	$(PREFIX)gcc
+export CXX		:=	$(PREFIX)g++
+export AR		:=	$(PREFIX)ar
+export OBJCOPY	:=	$(PREFIX)objcopy
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+export LD		:=	$(CXX)
+#export LD		:=	$(CC)
+ 
+CFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+CPPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+SFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+PCXFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcx)))
+BINFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin)))
+PALFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pal)))
+RAWFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.raw)))
+MAPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.map)))
+ 
+export OFILES	:=	$(MAPFILES:.map=.o) $(RAWFILES:.raw=.o) $(PALFILES:.pal=.o) $(BINFILES:.bin=.o) $(PCXFILES:.pcx=.o)\
+					$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+ 
+export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -I- -I$(CURDIR)/../commoninclude\
+					$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+					$(foreach dir,$(LIBDIRS),-I$(dir)/include/NDS)\
+					-I$(CURDIR)/$(BUILD) 
+ 
+export LIBPATHS	:=	$(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+ 
+.PHONY: $(BUILD) clean
+ 
+#---------------------------------------------------------------------------------
+$(BUILD):
+	@[ -d $@ ] || mkdir -p $@
+	@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+ 
+#---------------------------------------------------------------------------------
+clean:
+	@echo clean ...$(TARGET)
+	@rm -fr $(BUILD) *.bin
+ 
+ 
+#---------------------------------------------------------------------------------
+else
+ 
+DEPENDS	:=	$(OFILES:.o=.d)
+ 
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+
+$(OUTPUT).bin	:	$(OUTPUT).elf
+ 
+$(OUTPUT).elf	:	$(OFILES)
+ 
+
+
+#---------------------------------------------------------------------------------
+%.bin: %.elf
+	@echo built ... $(notdir $@)
+	@$(OBJCOPY) -O binary  $(TARGET).elf $@
+ 
+#---------------------------------------------------------------------------------
+%.elf:
+	echo ELF
+	@$(LD)  $(LDFLAGS) -specs=ds_arm7.specs $(OFILES) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
+ 
+ 
+ 
+#---------------------------------------------------------------------------------
+# Compile Targets for C/C++
+#---------------------------------------------------------------------------------
+ 
+#---------------------------------------------------------------------------------
+%.o : %.cpp
+	@echo $(notdir $<)
+	@echo $(CXX) -MM $(CXXFLAGS) -o $*.d $<
+	@$(CXX) -MM $(CXXFLAGS) -o $*.d $<
+	@$(CXX) $(CXXFLAGS) -c $< -o$@
+ 
+#---------------------------------------------------------------------------------
+%.o : %.c
+	@echo $(notdir $<)
+	@$(CC) -MM $(CFLAGS) -o $*.d $<
+	@$(CC)  $(CFLAGS) -c $< -o$@
+ 
+#---------------------------------------------------------------------------------
+%.o : %.s
+	@echo $(notdir $<)
+	@$(CC) -MM $(CFLAGS) -o $*.d $<
+	@$(CC)  $(ASFLAGS) -c $< -o$@
+ 
+define bin2o
+	cp $(<) $(*).tmp
+	$(OBJCOPY) -I binary -O elf32-littlearm -B arm \
+	--rename-section .data=.rodata \
+	--redefine-sym _binary_$*_tmp_start=$*\
+	--redefine-sym _binary_$*_tmp_end=$*_end\
+	--redefine-sym _binary_$*_tmp_size=$*_size\
+	$(*).tmp $(@)
+	echo "extern const u8" $(*)"[];" > $(*).h
+	echo "extern const u32" $(*)_size[]";" >> $(*).h
+	rm $(*).tmp
+endef
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pcx
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.bin
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.raw
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pal
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.map
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.o	:	%.mdl
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+ 
+-include $(DEPENDS)
+ 
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------
+.SUFFIXES:
+#---------------------------------------------------------------------------------
+ 
+#---------------------------------------------------------------------------------
+# TARGET is the name of the output, if this ends with _mb generates a multiboot image
+# BUILD is the directory where object files & intermediate files will be placed
+# SOURCES is a list of directories containing source code
+# INCLUDES is a list of directories containing extra header files
+#---------------------------------------------------------------------------------
+TARGET	:=	arm7
+BUILD		:=	build
+SOURCES	:=	gfx source data  
+INCLUDES	:=	include build
+ 
+#---------------------------------------------------------------------------------
+# options for code generation
+#---------------------------------------------------------------------------------
+ARCH	:=	-mthumb-interwork
+
+# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD
+# *insists* it has a FPU or VFP, and it won't take no for an answer!
+CFLAGS	:=	-g -Wall -O2\
+ 		-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
+		-ffast-math \
+		$(ARCH)
+
+CFLAGS	+=	$(INCLUDE) -DARM7
+
+CXXFLAGS	:=	$(CFLAGS) -fno-exceptions -fno-rtti
+ASFLAGS	:=	-g $(ARCH)
+LDFLAGS	:=	-g $(ARCH) -mno-fpu
+
+#---------------------------------------------------------------------------------
+# path to tools - this can be deleted if you set the path in windows
+#---------------------------------------------------------------------------------
+# export PATH		:=	/d/dev/ds/devkitARM_r11/bin:/bin
+ 
+#---------------------------------------------------------------------------------
+# PATH to ndslib - just make a system variable called NDSLIBPATH and be done with it
+#---------------------------------------------------------------------------------
+# NDSLIBPATH	:=	/d/dev/ds/ndslib/
+ 
+#---------------------------------------------------------------------------------
+# the prefix on the compiler executables
+#---------------------------------------------------------------------------------
+PREFIX			:=	arm-eabi-
+#---------------------------------------------------------------------------------
+# any extra libraries we wish to link with the project
+#---------------------------------------------------------------------------------
+LIBS	:= -lnds7
+ 
+ 
+#---------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# include and lib
+#---------------------------------------------------------------------------------
+LIBDIRS	:=	$(DEVKITPRO)/libnds
+ 
+ 
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+ 
+export OUTPUT	:=	$(CURDIR)/$(TARGET)
+ 
+export VPATH	:=	$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
+ 
+export CC		:=	$(PREFIX)gcc
+export CXX		:=	$(PREFIX)g++
+export AR		:=	$(PREFIX)ar
+export OBJCOPY	:=	$(PREFIX)objcopy
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+export LD		:=	$(CXX)
+#export LD		:=	$(CC)
+ 
+CFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+CPPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+SFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+PCXFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcx)))
+BINFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin)))
+PALFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pal)))
+RAWFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.raw)))
+MAPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.map)))
+ 
+export OFILES	:=	$(MAPFILES:.map=.o) $(RAWFILES:.raw=.o) $(PALFILES:.pal=.o) $(BINFILES:.bin=.o) $(PCXFILES:.pcx=.o)\
+					$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+ 
+export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -I- -I$(CURDIR)/../commoninclude\
+					$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+					$(foreach dir,$(LIBDIRS),-I$(dir)/include/NDS)\
+					-I$(CURDIR)/$(BUILD) 
+ 
+export LIBPATHS	:=	$(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+ 
+.PHONY: $(BUILD) clean
+ 
+#---------------------------------------------------------------------------------
+$(BUILD):
+	@[ -d $@ ] || mkdir -p $@
+	@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+ 
+#---------------------------------------------------------------------------------
+clean:
+	@echo clean ...$(TARGET)
+	@rm -fr $(BUILD) *.bin
+ 
+ 
+#---------------------------------------------------------------------------------
+else
+ 
+DEPENDS	:=	$(OFILES:.o=.d)
+ 
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+
+$(OUTPUT).bin	:	$(OUTPUT).elf
+ 
+$(OUTPUT).elf	:	$(OFILES)
+ 
+
+
+#---------------------------------------------------------------------------------
+%.bin: %.elf
+	@echo built ... $(notdir $@)
+	@$(OBJCOPY) -O binary  $(TARGET).elf $@
+ 
+#---------------------------------------------------------------------------------
+%.elf:
+	echo ELF
+	@$(LD)  $(LDFLAGS) -specs=ds_arm7.specs $(OFILES) $(LIBPATHS) $(LIBS) -o $(TARGET).elf
+ 
+ 
+ 
+#---------------------------------------------------------------------------------
+# Compile Targets for C/C++
+#---------------------------------------------------------------------------------
+ 
+#---------------------------------------------------------------------------------
+%.o : %.cpp
+	@echo $(notdir $<)
+	@echo $(CXX) -MM $(CXXFLAGS) -o $*.d $<
+	@$(CXX) -MM $(CXXFLAGS) -o $*.d $<
+	@$(CXX) $(CXXFLAGS) -c $< -o$@
+ 
+#---------------------------------------------------------------------------------
+%.o : %.c
+	@echo $(notdir $<)
+	@$(CC) -MM $(CFLAGS) -o $*.d $<
+	@$(CC)  $(CFLAGS) -c $< -o$@
+ 
+#---------------------------------------------------------------------------------
+%.o : %.s
+	@echo $(notdir $<)
+	@$(CC) -MM $(CFLAGS) -o $*.d $<
+	@$(CC)  $(ASFLAGS) -c $< -o$@
+ 
+define bin2o
+	cp $(<) $(*).tmp
+	$(OBJCOPY) -I binary -O elf32-littlearm -B arm \
+	--rename-section .data=.rodata \
+	--redefine-sym _binary_$*_tmp_start=$*\
+	--redefine-sym _binary_$*_tmp_end=$*_end\
+	--redefine-sym _binary_$*_tmp_size=$*_size\
+	$(*).tmp $(@)
+	echo "extern const u8" $(*)"[];" > $(*).h
+	echo "extern const u32" $(*)_size[]";" >> $(*).h
+	rm $(*).tmp
+endef
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pcx
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.bin
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.raw
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pal
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.map
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.o	:	%.mdl
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+ 
+-include $(DEPENDS)
+ 
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
\ No newline at end of file


Property changes on: scummvm/trunk/backends/platform/ds/arm7/Makefile
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm7/source/main.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm7/source/main.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm7/source/main.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,1130 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Header: /cvsroot/scummvm/scummvm/backends/fs/fs.cpp,v 1.3.2.1 2004/12/18 02:33:52 fingolfin Exp $
+ */
+
+//////////////////////////////////////////////////////////////////////
+// Simple ARM7 stub (sends RTC, TSC, and X/Y data to the ARM 9)
+// -- joat
+// -- modified by Darkain and others
+//////////////////////////////////////////////////////////////////////
+
+ 
+#include <nds.h>
+ 
+#include <bios.h>
+#include <arm7/touch.h>
+#include <arm7/clock.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nds/scummvm_ipc.h>
+//////////////////////////////////////////////////////////////////////
+
+
+#define TOUCH_CAL_X1 (*(vs16*)0x027FFCD8)
+#define TOUCH_CAL_Y1 (*(vs16*)0x027FFCDA)
+#define TOUCH_CAL_X2 (*(vs16*)0x027FFCDE)
+#define TOUCH_CAL_Y2 (*(vs16*)0x027FFCE0)
+#define SCREEN_WIDTH    256
+#define SCREEN_HEIGHT   192
+s32 TOUCH_WIDTH  = TOUCH_CAL_X2 - TOUCH_CAL_X1;
+s32 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
+s32 TOUCH_OFFSET_X = ( ((SCREEN_WIDTH -60) * TOUCH_CAL_X1) / TOUCH_WIDTH  ) - 28;
+s32 TOUCH_OFFSET_Y = ( ((SCREEN_HEIGHT-60) * TOUCH_CAL_Y1) / TOUCH_HEIGHT ) - 28;
+
+vu8* soundData;
+
+vu8* soundBuffer;
+vu8* arm9Buffer;
+bool soundFilled[4];
+
+int playingSection;
+
+bool needSleep = false;
+int temp;
+
+int adpcmBufferNum = 0;
+
+// those are pixel positions of the two points you click when calibrating
+#define TOUCH_CNTRL_X1   (*(vu8*)0x027FFCDC)
+#define TOUCH_CNTRL_Y1   (*(vu8*)0x027FFCDD)
+#define TOUCH_CNTRL_X2   (*(vu8*)0x027FFCE2)
+#define TOUCH_CNTRL_Y2   (*(vu8*)0x027FFCE3)
+
+
+//////////////////////////////////////////////////////////////////////
+
+/*
+void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F,  u8 pan=63, u8 format=0) {
+  SCHANNEL_TIMER(channel)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel) = (uint32)data;
+  SCHANNEL_LENGTH(channel) = bytes;
+  SCHANNEL_CR(channel)     = SOUND_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | (format==1?SOUND_8BIT:SOUND_16BIT);
+}
+
+
+s8 getFreeSoundChannel() {
+  for (int i=0; i<16; i++) {
+    if ( (SCHANNEL_CR(i) & SOUND_ENABLE) == 0 ) return i;
+  }
+  return -1;
+}
+*/
+
+
+s8 getFreeSoundChannel() {
+//  return 0;
+  for (int i=0; i<16; i++) {
+    if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 ) return i;
+  }
+  return -1;
+}
+
+void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F,  u8 pan=63, u8 format=0) {
+  REG_IME = IME_DISABLE;
+
+  channel = getFreeSoundChannel();
+/*  if (format == 2) {
+	channel = 1;
+  } else {
+	channel = 0;
+  }*/
+  
+  if (channel > 1) channel = 1;
+  
+  bytes &= ~7;		// Multiple of 4 bytes!
+//  bytes += 4;
+  
+  SCHANNEL_CR(channel) = 0;
+  SCHANNEL_TIMER(channel)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel) = ((uint32) (data));
+  SCHANNEL_LENGTH(channel) = ((bytes & 0x7FFFFFFF) >> 2);
+  SCHANNEL_REPEAT_POINT(channel) = 0;
+
+  SCHANNEL_CR(channel + 2) = 0;
+  SCHANNEL_TIMER(channel + 2)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel + 2) = ((uint32) (data));
+  SCHANNEL_LENGTH(channel + 2) = ((bytes & 0x7FFFFFFF) >> 2);
+  SCHANNEL_REPEAT_POINT(channel + 2) = 0;
+  
+  uint32 flags = SCHANNEL_ENABLE | SOUND_VOL(vol) | SOUND_PAN(pan);
+
+  switch (format) {
+	case 1: {
+		flags |= SOUND_8BIT;
+		flags |= SOUND_REPEAT;// | (1 << 15);
+		break;
+	}
+	
+	case 0: {
+		flags |= SOUND_16BIT;
+		flags |= SOUND_REPEAT;// | (1 << 15);
+		break;
+	}
+	
+	case 2: {
+		flags |= SOUND_FORMAT_ADPCM;
+		flags |= SOUND_ONE_SHOT;// | (1 << 15);
+		
+		SCHANNEL_SOURCE(channel) = (unsigned int) IPC->adpcm.buffer[0];
+		//bytes += 32;
+		SCHANNEL_LENGTH(channel) = (((bytes + 4) & 0x7FFFFFFF) >> 2);
+		
+		SCHANNEL_CR(channel + 1) = 0;
+		SCHANNEL_SOURCE(channel + 1) = (unsigned int) IPC->adpcm.buffer[0];
+		SCHANNEL_LENGTH(channel + 1) = (((bytes + 4) & 0x7FFFFFFF) >> 2);
+		SCHANNEL_TIMER(channel + 1) = SOUND_FREQ(sampleRate);
+		SCHANNEL_REPEAT_POINT(channel + 1) = 0;
+		SCHANNEL_CR(channel + 1) = flags;
+		temp = bytes;
+		adpcmBufferNum = 0;
+		break;
+	}
+  }
+	
+  
+//  if (bytes & 0x80000000) {
+//    flags |= SOUND_REPEAT;
+//  } else {
+//  }
+
+  
+   
+  
+  soundData = (vu8* ) data;
+
+  SCHANNEL_CR(channel)     = flags;
+  SCHANNEL_CR(channel + 2)     = flags;
+
+
+
+  if (channel == 0) {
+	for (volatile int i = 0; i < 16384 * 2; i++) {
+		// Delay loop - this makes everything stay in sync!
+	}
+		
+	TIMER0_CR = 0;
+	TIMER0_DATA = SOUND_FREQ(sampleRate) * 2;
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1;
+		
+	TIMER1_CR = 0;
+	TIMER1_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3);		// Trigger four times during the length of the buffer
+	TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+
+    playingSection = 0;
+  } else {
+	for (volatile int i = 0; i < 16384 * 2; i++) {
+		// Delay loop - this makes everything stay in sync!
+	}
+		
+	TIMER2_CR = 0;
+	TIMER2_DATA = SOUND_FREQ(sampleRate) * 2;
+	TIMER2_CR = TIMER_ENABLE | TIMER_DIV_1;
+		
+	TIMER3_CR = 0;
+	TIMER3_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3);		// Trigger four times during the length of the buffer
+	TIMER3_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+	
+	for (int r = 0; r < 4; r++) {
+//		IPC->streamFillNeeded[r] = true;
+	}
+	
+	IPC->streamPlayingSection = 0;
+  }
+
+
+
+//  IPC->fillSoundFirstHalf = true;
+//  IPC->fillSoundSecondHalf = true;
+//  soundFirstHalf = true;
+  
+  REG_IME = IME_ENABLE;
+}
+
+void stopSound(int chan) {
+ SCHANNEL_CR(chan) = 0;
+}
+
+void DummyHandler() {
+	REG_IF = REG_IF;
+}
+
+uint16 powerManagerWrite(uint32 command, u32 data, bool enable) {
+
+  uint16 result;
+  SerialWaitBusy();
+
+  // Write the command and wait for it to complete
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11);
+  REG_SPIDATA = command | 0x80;
+  SerialWaitBusy();
+
+  // Write the second command and clock in the data
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz;
+  REG_SPIDATA = 0;
+  SerialWaitBusy();
+  
+  result = REG_SPIDATA & 0xFF;
+
+
+
+  // Write the command and wait for it to complete
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11);
+  REG_SPIDATA = command;
+  SerialWaitBusy();
+
+  // Write the second command and clock in the data
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz;
+  REG_SPIDATA = enable? (result | data): (result & ~data);
+  SerialWaitBusy();
+}
+
+/*
+void performSleep() {
+
+  powerManagerWrite(0, 0x30, true);
+
+  // Here, I set up a dummy interrupt handler, then trigger all interrupts.
+  // These are just aknowledged by the handler without doing anything else.
+  // Why?  Because without it the sleep mode will only happen once, and then
+  // never again.  I got the idea from reading the MoonShell source.
+  IME = 0;
+  u32 irq = (u32) IRQ_HANDLER;
+  IRQ_HANDLER = DummyHandler;
+  IF = ~0;
+  IME = 1;
+  
+  
+  // Now save which interrupts are enabled, then set only the screens unfolding
+  // interrupt to be enabled, so that the first interrupt that happens is the
+  // one I want.
+  int saveInts = IE;
+  
+  
+  
+  IE = IRQ_TIMER0;		// Screens unfolding interrupt
+
+  // Now call the sleep function in the bios
+  bool b;
+  do {
+    TIMER0_CR = 0;
+	TIMER0_DATA = TIMER_FREQ(20);
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_64;
+	
+	swiDelay(100);
+  
+	swiSleep();
+
+	swiDelay(100);
+	
+	powerManagerWrite(0, 0x30, b = !b);	
+  } while (!(TIMER0_CR & TIMER_ENABLE));
+  
+  TIMER0_CR = 0;
+
+  // We're back from sleep, now restore the interrupt state and IRQ handler  
+  IRQ_HANDLER = (void (*)()) irq;
+  IE = saveInts;
+  IF = ~0;
+  IME = 1;
+
+  
+  
+  powerManagerWrite(0, 0x30, false);
+}
+*/
+
+
+void performSleep() {
+  powerManagerWrite(0, 0x30, true);
+
+  IPC->performArm9SleepMode = true;	// Tell ARM9 to sleep
+  
+//  u32 irq = (u32) IRQ_HANDLER;
+//  IRQ_HANDLER = DummyHandler;
+//  POWER_CR &= ~POWER_SOUND;
+  
+//  int saveInts = REG_IE;
+//  REG_IE = (1 << 22) | IRQ_VBLANK;		// Lid open
+//  *((u32*) (0x0380FFF8)) = *((u32*) (0x0380FFF8)) | (REG_IE & REG_IF);
+//  VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK;
+
+  
+  int r = 0;
+  while ((REG_KEYXY & (1 << 7))) {		// Wait for lid to open
+	swiDelay(1000000);
+	r++;
+  }
+  
+//  IRQ_HANDLER = (void (*)()) irq;
+  IPC->performArm9SleepMode = false;	// Tell ARM9 to wake up
+//  REG_IE = saveInts;
+  
+//  POWER_CR |= POWER_SOUND;
+ 
+  powerManagerWrite(0, 0x30, false);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+
+void InterruptHandler(void) {
+  static int heartbeat = 0;
+
+  if (REG_IF & IRQ_TIMER1) {
+	
+	IPC->fillNeeded[playingSection] = true;
+	soundFilled[playingSection] = false;
+	  
+	if (playingSection == 3) {
+//		IME = IME_DISABLED;
+		
+	//	while (SCHANNEL_CR(0) & SCHANNEL_ENABLE) {
+	//	}
+//		SCHANNEL_CR(0) &= ~SCHANNEL_ENABLE;	
+		
+//		SCHANNEL_CR(0) |= SCHANNEL_ENABLE;
+//		TIMER1_CR = 0;
+//		TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+		
+		playingSection = 0;
+		
+//		IME = IME_ENABLED;
+	} else {
+		playingSection++;
+	}
+	
+	IPC->playingSection = playingSection;
+	
+/*	for (int r = 0; r < 4; r++) {
+		//if ((!soundFilled[r]) && (!IPC->fillNeeded[playingSection])) {
+			memcpy((void *) (soundBuffer + (r * 1024)), (void *) (arm9Buffer + (r * 1024)), 1024);
+
+			vu16* p = (vu16 *) (soundBuffer);
+			//for (int t = 0; t < 2048; t++) {
+		//		*(p + t) = (t & 1)? 0xF000: 0x0000;
+			//}
+			soundFilled[r] = true;
+		//}
+	}*/
+	
+
+    REG_IF = IRQ_TIMER1;
+  }
+  
+
+  if (REG_IF & IRQ_TIMER3) {
+	while (IPC->adpcm.semaphore);		// Wait for buffer to become free if needed
+	IPC->adpcm.semaphore = true;		// Lock the buffer structure to prevent clashing with the ARM7
+		
+	IPC->streamFillNeeded[IPC->streamPlayingSection] = true;
+	  
+	if (IPC->streamPlayingSection == 3) {
+		IPC->streamPlayingSection = 0;
+	} else {
+		IPC->streamPlayingSection++;
+	}
+	
+    REG_IF = IRQ_TIMER3;
+	
+	IPC->adpcm.semaphore = false;
+  }
+
+
+//  IPC->performArm9SleepMode = false;
+
+	// precalculate some values
+//  static int16 TOUCH_WIDTH  = TOUCH_CAL_X2 - TOUCH_CAL_X1;
+//  static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
+//  static int16 CNTRL_WIDTH  = TOUCH_CNTRL_X2 - (TOUCH_CNTRL_X1 - 8);
+//  static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - (TOUCH_CNTRL_Y1 - 8);
+  
+  
+  
+ 
+ 
+  if (REG_IF & IRQ_VBLANK) {
+    uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0;
+    int t1=0, t2=0;
+    uint32 temp=0;
+    uint8 ct[sizeof(IPC->curtime)];
+
+    
+    // Update the heartbeat
+    heartbeat++;
+ 
+    // Read the X/Y buttons and the /PENIRQ line
+    but = REG_KEYXY;
+    if (!(but & 0x40)) {
+      // Read the touch screen
+	  touchPosition p = touchReadXY();
+
+//      x = touchRead(TSC_MEASURE_X);
+ //     y = touchRead(TSC_MEASURE_Y);
+	  
+	  x = p.x;
+	  y = p.y;
+	  
+	  xpx = p.px;
+	  ypx = p.py;
+	  
+//      xpx = ( ((SCREEN_WIDTH -60) * x) / TOUCH_WIDTH  ) - TOUCH_OFFSET_X;
+  //    ypx = ( ((SCREEN_HEIGHT-60) * y) / TOUCH_HEIGHT ) - TOUCH_OFFSET_Y;
+	  
+//	  xpx = (IPC->touchX - (int16) TOUCH_CAL_X1) * CNTRL_WIDTH  / TOUCH_WIDTH  + (int16) (TOUCH_CNTRL_X1 - 8);
+	//  ypx = (IPC->touchY - (int16) TOUCH_CAL_Y1) * CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) (TOUCH_CNTRL_Y1 - 8); 
+
+	  
+      z1 = touchRead(TSC_MEASURE_Z1);
+      z2 = touchRead(TSC_MEASURE_Z2);
+    }
+	
+    if (but & (1 << 7)) {		// Check if screen is folded
+	  needSleep = true;
+	}
+	
+
+    batt = touchRead(TSC_MEASURE_BATTERY);
+    aux  = touchRead(TSC_MEASURE_AUX);
+
+    // Read the time
+    rtcGetTime((uint8 *)ct);
+    BCDToInteger((uint8 *)&(ct[1]), 7);
+ 
+    // Read the temperature
+    temp = touchReadTemperature(&t1, &t2);
+ 
+    // Update the IPC struct
+    IPC->heartbeat = heartbeat;
+    IPC->buttons   = but;
+    IPC->touchX    = x;
+    IPC->touchY    = y;
+    IPC->touchXpx  = xpx;
+    IPC->touchYpx  = ypx;
+    IPC->touchZ1   = z1;
+    IPC->touchZ2   = z2;
+    IPC->battery   = batt;
+    IPC->aux       = aux;
+
+    for(u32 i=0; i<sizeof(ct); i++) {
+      IPC->curtime[i] = ct[i];
+    }
+
+    IPC->temperature = temp;
+    IPC->tdiode1 = t1;
+    IPC->tdiode2 = t2;
+
+   
+
+	//sound code  :)
+    TransferSound *snd = IPC->soundData;
+    IPC->soundData = 0;
+    if (snd) {
+      for (int i=0; i<snd->count; i++) {
+        s8 chan = getFreeSoundChannel();
+		if (snd->data[i].rate > 0) {
+			if (chan >= 0) {
+			  startSound(snd->data[i].rate, snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan, snd->data[i].format);
+			}
+		} else {
+			stopSound(-snd->data[i].rate);
+		}
+      }
+    } 
+
+    REG_IF = IRQ_VBLANK;
+  }
+ 
+}
+ 
+
+//////////////////////////////////////////////////////////////////////
+ 
+
+int main(int argc, char ** argv) {
+  // Reset the clock if needed
+  rtcReset();
+
+  //enable sound
+  powerON(POWER_SOUND);
+  SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F);
+  IPC->soundData = 0;
+  IPC->reset = false;
+  
+  
+  for (int r = 0; r < 8; r++) {
+	IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512);
+  }
+  
+  for (int r = 0; r < 4; r++) {
+	soundFilled[r] = false;
+  }
+
+ 
+  // Set up the interrupt handler
+  REG_IME = 0;
+  IRQ_HANDLER = &InterruptHandler;
+  REG_IE = IRQ_VBLANK | IRQ_TIMER1 | IRQ_TIMER3;
+  REG_IF = ~0;
+  DISP_SR = DISP_VBLANK_IRQ;
+  REG_IME = 1;
+  
+  
+
+  // Keep the ARM7 out of main RAM
+  while (1) {
+	if (needSleep) {
+		performSleep();
+		needSleep = false;
+	}
+//	if (IPC->reset) {
+//		swiSoftReset();
+//	}
+  }
+  return 0;
+}
+
+ 
+//////////////////////////////////////////////////////////////////////
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Header: /cvsroot/scummvm/scummvm/backends/fs/fs.cpp,v 1.3.2.1 2004/12/18 02:33:52 fingolfin Exp $
+ */
+
+//////////////////////////////////////////////////////////////////////
+// Simple ARM7 stub (sends RTC, TSC, and X/Y data to the ARM 9)
+// -- joat
+// -- modified by Darkain and others
+//////////////////////////////////////////////////////////////////////
+
+ 
+#include <nds.h>
+ 
+#include <bios.h>
+#include <arm7/touch.h>
+#include <arm7/clock.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nds/scummvm_ipc.h>
+//////////////////////////////////////////////////////////////////////
+
+
+#define TOUCH_CAL_X1 (*(vs16*)0x027FFCD8)
+#define TOUCH_CAL_Y1 (*(vs16*)0x027FFCDA)
+#define TOUCH_CAL_X2 (*(vs16*)0x027FFCDE)
+#define TOUCH_CAL_Y2 (*(vs16*)0x027FFCE0)
+#define SCREEN_WIDTH    256
+#define SCREEN_HEIGHT   192
+s32 TOUCH_WIDTH  = TOUCH_CAL_X2 - TOUCH_CAL_X1;
+s32 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
+s32 TOUCH_OFFSET_X = ( ((SCREEN_WIDTH -60) * TOUCH_CAL_X1) / TOUCH_WIDTH  ) - 28;
+s32 TOUCH_OFFSET_Y = ( ((SCREEN_HEIGHT-60) * TOUCH_CAL_Y1) / TOUCH_HEIGHT ) - 28;
+
+vu8* soundData;
+
+vu8* soundBuffer;
+vu8* arm9Buffer;
+bool soundFilled[4];
+
+int playingSection;
+
+bool needSleep = false;
+int temp;
+
+int adpcmBufferNum = 0;
+
+// those are pixel positions of the two points you click when calibrating
+#define TOUCH_CNTRL_X1   (*(vu8*)0x027FFCDC)
+#define TOUCH_CNTRL_Y1   (*(vu8*)0x027FFCDD)
+#define TOUCH_CNTRL_X2   (*(vu8*)0x027FFCE2)
+#define TOUCH_CNTRL_Y2   (*(vu8*)0x027FFCE3)
+
+
+//////////////////////////////////////////////////////////////////////
+
+/*
+void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F,  u8 pan=63, u8 format=0) {
+  SCHANNEL_TIMER(channel)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel) = (uint32)data;
+  SCHANNEL_LENGTH(channel) = bytes;
+  SCHANNEL_CR(channel)     = SOUND_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | (format==1?SOUND_8BIT:SOUND_16BIT);
+}
+
+
+s8 getFreeSoundChannel() {
+  for (int i=0; i<16; i++) {
+    if ( (SCHANNEL_CR(i) & SOUND_ENABLE) == 0 ) return i;
+  }
+  return -1;
+}
+*/
+
+
+s8 getFreeSoundChannel() {
+//  return 0;
+  for (int i=0; i<16; i++) {
+    if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 ) return i;
+  }
+  return -1;
+}
+
+void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F,  u8 pan=63, u8 format=0) {
+  REG_IME = IME_DISABLE;
+
+  channel = getFreeSoundChannel();
+/*  if (format == 2) {
+	channel = 1;
+  } else {
+	channel = 0;
+  }*/
+  
+  if (channel > 1) channel = 1;
+  
+  bytes &= ~7;		// Multiple of 4 bytes!
+//  bytes += 4;
+  
+  SCHANNEL_CR(channel) = 0;
+  SCHANNEL_TIMER(channel)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel) = ((uint32) (data));
+  SCHANNEL_LENGTH(channel) = ((bytes & 0x7FFFFFFF) >> 2);
+  SCHANNEL_REPEAT_POINT(channel) = 0;
+
+  SCHANNEL_CR(channel + 2) = 0;
+  SCHANNEL_TIMER(channel + 2)  = SOUND_FREQ(sampleRate);
+  SCHANNEL_SOURCE(channel + 2) = ((uint32) (data));
+  SCHANNEL_LENGTH(channel + 2) = ((bytes & 0x7FFFFFFF) >> 2);
+  SCHANNEL_REPEAT_POINT(channel + 2) = 0;
+  
+  uint32 flags = SCHANNEL_ENABLE | SOUND_VOL(vol) | SOUND_PAN(pan);
+
+  switch (format) {
+	case 1: {
+		flags |= SOUND_8BIT;
+		flags |= SOUND_REPEAT;// | (1 << 15);
+		break;
+	}
+	
+	case 0: {
+		flags |= SOUND_16BIT;
+		flags |= SOUND_REPEAT;// | (1 << 15);
+		break;
+	}
+	
+	case 2: {
+		flags |= SOUND_FORMAT_ADPCM;
+		flags |= SOUND_ONE_SHOT;// | (1 << 15);
+		
+		SCHANNEL_SOURCE(channel) = (unsigned int) IPC->adpcm.buffer[0];
+		//bytes += 32;
+		SCHANNEL_LENGTH(channel) = (((bytes + 4) & 0x7FFFFFFF) >> 2);
+		
+		SCHANNEL_CR(channel + 1) = 0;
+		SCHANNEL_SOURCE(channel + 1) = (unsigned int) IPC->adpcm.buffer[0];
+		SCHANNEL_LENGTH(channel + 1) = (((bytes + 4) & 0x7FFFFFFF) >> 2);
+		SCHANNEL_TIMER(channel + 1) = SOUND_FREQ(sampleRate);
+		SCHANNEL_REPEAT_POINT(channel + 1) = 0;
+		SCHANNEL_CR(channel + 1) = flags;
+		temp = bytes;
+		adpcmBufferNum = 0;
+		break;
+	}
+  }
+	
+  
+//  if (bytes & 0x80000000) {
+//    flags |= SOUND_REPEAT;
+//  } else {
+//  }
+
+  
+   
+  
+  soundData = (vu8* ) data;
+
+  SCHANNEL_CR(channel)     = flags;
+  SCHANNEL_CR(channel + 2)     = flags;
+
+
+
+  if (channel == 0) {
+	for (volatile int i = 0; i < 16384 * 2; i++) {
+		// Delay loop - this makes everything stay in sync!
+	}
+		
+	TIMER0_CR = 0;
+	TIMER0_DATA = SOUND_FREQ(sampleRate) * 2;
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1;
+		
+	TIMER1_CR = 0;
+	TIMER1_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3);		// Trigger four times during the length of the buffer
+	TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+
+    playingSection = 0;
+  } else {
+	for (volatile int i = 0; i < 16384 * 2; i++) {
+		// Delay loop - this makes everything stay in sync!
+	}
+		
+	TIMER2_CR = 0;
+	TIMER2_DATA = SOUND_FREQ(sampleRate) * 2;
+	TIMER2_CR = TIMER_ENABLE | TIMER_DIV_1;
+		
+	TIMER3_CR = 0;
+	TIMER3_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3);		// Trigger four times during the length of the buffer
+	TIMER3_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+	
+	for (int r = 0; r < 4; r++) {
+//		IPC->streamFillNeeded[r] = true;
+	}
+	
+	IPC->streamPlayingSection = 0;
+  }
+
+
+
+//  IPC->fillSoundFirstHalf = true;
+//  IPC->fillSoundSecondHalf = true;
+//  soundFirstHalf = true;
+  
+  REG_IME = IME_ENABLE;
+}
+
+void stopSound(int chan) {
+ SCHANNEL_CR(chan) = 0;
+}
+
+void DummyHandler() {
+	REG_IF = REG_IF;
+}
+
+uint16 powerManagerWrite(uint32 command, u32 data, bool enable) {
+
+  uint16 result;
+  SerialWaitBusy();
+
+  // Write the command and wait for it to complete
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11);
+  REG_SPIDATA = command | 0x80;
+  SerialWaitBusy();
+
+  // Write the second command and clock in the data
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz;
+  REG_SPIDATA = 0;
+  SerialWaitBusy();
+  
+  result = REG_SPIDATA & 0xFF;
+
+
+
+  // Write the command and wait for it to complete
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11);
+  REG_SPIDATA = command;
+  SerialWaitBusy();
+
+  // Write the second command and clock in the data
+  REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz;
+  REG_SPIDATA = enable? (result | data): (result & ~data);
+  SerialWaitBusy();
+}
+
+/*
+void performSleep() {
+
+  powerManagerWrite(0, 0x30, true);
+
+  // Here, I set up a dummy interrupt handler, then trigger all interrupts.
+  // These are just aknowledged by the handler without doing anything else.
+  // Why?  Because without it the sleep mode will only happen once, and then
+  // never again.  I got the idea from reading the MoonShell source.
+  IME = 0;
+  u32 irq = (u32) IRQ_HANDLER;
+  IRQ_HANDLER = DummyHandler;
+  IF = ~0;
+  IME = 1;
+  
+  
+  // Now save which interrupts are enabled, then set only the screens unfolding
+  // interrupt to be enabled, so that the first interrupt that happens is the
+  // one I want.
+  int saveInts = IE;
+  
+  
+  
+  IE = IRQ_TIMER0;		// Screens unfolding interrupt
+
+  // Now call the sleep function in the bios
+  bool b;
+  do {
+    TIMER0_CR = 0;
+	TIMER0_DATA = TIMER_FREQ(20);
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_64;
+	
+	swiDelay(100);
+  
+	swiSleep();
+
+	swiDelay(100);
+	
+	powerManagerWrite(0, 0x30, b = !b);	
+  } while (!(TIMER0_CR & TIMER_ENABLE));
+  
+  TIMER0_CR = 0;
+
+  // We're back from sleep, now restore the interrupt state and IRQ handler  
+  IRQ_HANDLER = (void (*)()) irq;
+  IE = saveInts;
+  IF = ~0;
+  IME = 1;
+
+  
+  
+  powerManagerWrite(0, 0x30, false);
+}
+*/
+
+
+void performSleep() {
+  powerManagerWrite(0, 0x30, true);
+
+  IPC->performArm9SleepMode = true;	// Tell ARM9 to sleep
+  
+//  u32 irq = (u32) IRQ_HANDLER;
+//  IRQ_HANDLER = DummyHandler;
+//  POWER_CR &= ~POWER_SOUND;
+  
+//  int saveInts = REG_IE;
+//  REG_IE = (1 << 22) | IRQ_VBLANK;		// Lid open
+//  *((u32*) (0x0380FFF8)) = *((u32*) (0x0380FFF8)) | (REG_IE & REG_IF);
+//  VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK;
+
+  
+  int r = 0;
+  while ((REG_KEYXY & (1 << 7))) {		// Wait for lid to open
+	swiDelay(1000000);
+	r++;
+  }
+  
+//  IRQ_HANDLER = (void (*)()) irq;
+  IPC->performArm9SleepMode = false;	// Tell ARM9 to wake up
+//  REG_IE = saveInts;
+  
+//  POWER_CR |= POWER_SOUND;
+ 
+  powerManagerWrite(0, 0x30, false);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+
+void InterruptHandler(void) {
+  static int heartbeat = 0;
+
+  if (REG_IF & IRQ_TIMER1) {
+	
+	IPC->fillNeeded[playingSection] = true;
+	soundFilled[playingSection] = false;
+	  
+	if (playingSection == 3) {
+//		IME = IME_DISABLED;
+		
+	//	while (SCHANNEL_CR(0) & SCHANNEL_ENABLE) {
+	//	}
+//		SCHANNEL_CR(0) &= ~SCHANNEL_ENABLE;	
+		
+//		SCHANNEL_CR(0) |= SCHANNEL_ENABLE;
+//		TIMER1_CR = 0;
+//		TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+		
+		playingSection = 0;
+		
+//		IME = IME_ENABLED;
+	} else {
+		playingSection++;
+	}
+	
+	IPC->playingSection = playingSection;
+	
+/*	for (int r = 0; r < 4; r++) {
+		//if ((!soundFilled[r]) && (!IPC->fillNeeded[playingSection])) {
+			memcpy((void *) (soundBuffer + (r * 1024)), (void *) (arm9Buffer + (r * 1024)), 1024);
+
+			vu16* p = (vu16 *) (soundBuffer);
+			//for (int t = 0; t < 2048; t++) {
+		//		*(p + t) = (t & 1)? 0xF000: 0x0000;
+			//}
+			soundFilled[r] = true;
+		//}
+	}*/
+	
+
+    REG_IF = IRQ_TIMER1;
+  }
+  
+
+  if (REG_IF & IRQ_TIMER3) {
+	while (IPC->adpcm.semaphore);		// Wait for buffer to become free if needed
+	IPC->adpcm.semaphore = true;		// Lock the buffer structure to prevent clashing with the ARM7
+		
+	IPC->streamFillNeeded[IPC->streamPlayingSection] = true;
+	  
+	if (IPC->streamPlayingSection == 3) {
+		IPC->streamPlayingSection = 0;
+	} else {
+		IPC->streamPlayingSection++;
+	}
+	
+    REG_IF = IRQ_TIMER3;
+	
+	IPC->adpcm.semaphore = false;
+  }
+
+
+//  IPC->performArm9SleepMode = false;
+
+	// precalculate some values
+//  static int16 TOUCH_WIDTH  = TOUCH_CAL_X2 - TOUCH_CAL_X1;
+//  static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
+//  static int16 CNTRL_WIDTH  = TOUCH_CNTRL_X2 - (TOUCH_CNTRL_X1 - 8);
+//  static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - (TOUCH_CNTRL_Y1 - 8);
+  
+  
+  
+ 
+ 
+  if (REG_IF & IRQ_VBLANK) {
+    uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0;
+    int t1=0, t2=0;
+    uint32 temp=0;
+    uint8 ct[sizeof(IPC->curtime)];
+
+    
+    // Update the heartbeat
+    heartbeat++;
+ 
+    // Read the X/Y buttons and the /PENIRQ line
+    but = REG_KEYXY;
+    if (!(but & 0x40)) {
+      // Read the touch screen
+	  touchPosition p = touchReadXY();
+
+//      x = touchRead(TSC_MEASURE_X);
+ //     y = touchRead(TSC_MEASURE_Y);
+	  
+	  x = p.x;
+	  y = p.y;
+	  
+	  xpx = p.px;
+	  ypx = p.py;
+	  
+//      xpx = ( ((SCREEN_WIDTH -60) * x) / TOUCH_WIDTH  ) - TOUCH_OFFSET_X;
+  //    ypx = ( ((SCREEN_HEIGHT-60) * y) / TOUCH_HEIGHT ) - TOUCH_OFFSET_Y;
+	  
+//	  xpx = (IPC->touchX - (int16) TOUCH_CAL_X1) * CNTRL_WIDTH  / TOUCH_WIDTH  + (int16) (TOUCH_CNTRL_X1 - 8);
+	//  ypx = (IPC->touchY - (int16) TOUCH_CAL_Y1) * CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) (TOUCH_CNTRL_Y1 - 8); 
+
+	  
+      z1 = touchRead(TSC_MEASURE_Z1);
+      z2 = touchRead(TSC_MEASURE_Z2);
+    }
+	
+    if (but & (1 << 7)) {		// Check if screen is folded
+	  needSleep = true;
+	}
+	
+
+    batt = touchRead(TSC_MEASURE_BATTERY);
+    aux  = touchRead(TSC_MEASURE_AUX);
+
+    // Read the time
+    rtcGetTime((uint8 *)ct);
+    BCDToInteger((uint8 *)&(ct[1]), 7);
+ 
+    // Read the temperature
+    temp = touchReadTemperature(&t1, &t2);
+ 
+    // Update the IPC struct
+    IPC->heartbeat = heartbeat;
+    IPC->buttons   = but;
+    IPC->touchX    = x;
+    IPC->touchY    = y;
+    IPC->touchXpx  = xpx;
+    IPC->touchYpx  = ypx;
+    IPC->touchZ1   = z1;
+    IPC->touchZ2   = z2;
+    IPC->battery   = batt;
+    IPC->aux       = aux;
+
+    for(u32 i=0; i<sizeof(ct); i++) {
+      IPC->curtime[i] = ct[i];
+    }
+
+    IPC->temperature = temp;
+    IPC->tdiode1 = t1;
+    IPC->tdiode2 = t2;
+
+   
+
+	//sound code  :)
+    TransferSound *snd = IPC->soundData;
+    IPC->soundData = 0;
+    if (snd) {
+      for (int i=0; i<snd->count; i++) {
+        s8 chan = getFreeSoundChannel();
+		if (snd->data[i].rate > 0) {
+			if (chan >= 0) {
+			  startSound(snd->data[i].rate, snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan, snd->data[i].format);
+			}
+		} else {
+			stopSound(-snd->data[i].rate);
+		}
+      }
+    } 
+
+    REG_IF = IRQ_VBLANK;
+  }
+ 
+}
+ 
+
+//////////////////////////////////////////////////////////////////////
+ 
+
+int main(int argc, char ** argv) {
+  // Reset the clock if needed
+  rtcReset();
+
+  //enable sound
+  powerON(POWER_SOUND);
+  SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F);
+  IPC->soundData = 0;
+  IPC->reset = false;
+  
+  
+  for (int r = 0; r < 8; r++) {
+	IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512);
+  }
+  
+  for (int r = 0; r < 4; r++) {
+	soundFilled[r] = false;
+  }
+
+ 
+  // Set up the interrupt handler
+  REG_IME = 0;
+  IRQ_HANDLER = &InterruptHandler;
+  REG_IE = IRQ_VBLANK | IRQ_TIMER1 | IRQ_TIMER3;
+  REG_IF = ~0;
+  DISP_SR = DISP_VBLANK_IRQ;
+  REG_IME = 1;
+  
+  
+
+  // Keep the ARM7 out of main RAM
+  while (1) {
+	if (needSleep) {
+		performSleep();
+		needSleep = false;
+	}
+//	if (IPC->reset) {
+//		swiSoftReset();
+//	}
+  }
+  return 0;
+}
+
+ 
+//////////////////////////////////////////////////////////////////////
+


Property changes on: scummvm/trunk/backends/platform/ds/arm7/source/main.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/buildkeyboard.bat
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/buildkeyboard.bat	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/buildkeyboard.bat	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,8 @@
+cd data
+..\tools\gfx2gba -c16 -t8 -M -pkeyboard_pal.raw ..\keyboard.bmp
+del keyboard.map
+pause
+cd data
+..\tools\gfx2gba -c16 -t8 -M -pkeyboard_pal.raw ..\keyboard.bmp
+del keyboard.map
+pause
\ No newline at end of file


Property changes on: scummvm/trunk/backends/platform/ds/arm9/buildkeyboard.bat
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/lib/readme.txt
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/lib/readme.txt	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/lib/readme.txt	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,2 @@
+If building with MAD enabled, put libmad.a in here.
+If building with MAD enabled, put libmad.a in here.
\ No newline at end of file


Property changes on: scummvm/trunk/backends/platform/ds/arm9/lib/readme.txt
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/makefile
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/makefile	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/makefile	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,522 @@
+#BUILD_PLUGINS = 1
+libndsdir = $(DEVKITPRO)/libnds
+
+DS_SCUMM_BUILD = 1
+
+#DS_NON_SCUMM_BUILD = 1
+
+USE_MAD = 1
+
+VPATH = $(srcdir)
+
+# Command to build libmad is:
+# ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork'
+
+ifdef DS_NON_SCUMM_BUILD
+	DEFINES = -DDS_NON_SCUMM_BUILD
+	DISABLE_HE = 1
+	DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	#DISABLE_SIMON = 1
+	#DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	#DISABLE_QUEEN = 1
+	DISABLE_SAGA = 1
+	DISABLE_KYRA = 1
+	#DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	BUILD=scummvm-B
+endif
+
+ifdef DS_SCUMM_BUILD
+	DEFINES = -DDS_SCUMM_BUILD
+	DISABLE_HE = 1
+	#DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	DISABLE_SIMON = 1
+	DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	DISABLE_QUEEN = 1
+	DISABLE_SAGA = 1
+	DISABLE_KYRA = 1
+	DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	BUILD=scummvm-A
+endif
+
+ARM7BIN	:= -7 $(CURDIR)/../../arm7/arm7.bin
+ICON 		:= -b ../../../logo.bmp "ScummVM;By Neil Millstone;"
+
+CC      = arm-eabi-gcc
+CXX     = arm-eabi-g++
+
+CFLAGS	=	-Wno-multichar -Wall -Os\
+		-Wno-multichar -mcpu=arm9tdmi -mtune=arm9tdmi \
+ 		-mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
+		-ffast-math -mthumb-interwork
+		
+CXXFLAGS=	$(CFLAGS) -Wno-non-virtual-dtor	 -Wno-non-virtual-dtor \
+		-fno-exceptions -fno-rtti
+
+ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork
+DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES
+ifdef USE_MAD
+	DEFINES += -DUSE_MAD
+endif
+
+LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt
+
+INCLUDES= -I./ -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/common -I$(portdir)/source -I$(portdir)/source/compressor -I$(portdir)/source/fat \
+			-I$(srcdir)/backends/fs  -I$(srcdir)/backends/fs/ds -I$(portdir)/data -I$(libndsdir)/include -I$(portdir)/../commoninclude\
+			-I$(srcdir)/scumm -I$(libndsdir)/include -I$(libndsdir)/include/nds -I$(srcdir)/engines -I$(portdir)/source/mad
+			
+
+LIBS	= -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9
+ifdef USE_MAD
+	LIBS += -lmad
+endif
+
+#-Lscumm -lscumm -Lbase -lbase -Lcommon -lcommon -Lgraphics -lgraphics -Lgui -lgui -Lsound -lsound
+EXECUTABLE = scummvm.elf
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = plugin.x plugin.syms scummvm.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,-Tplugin.x,--just-symbols,scummvm.elf,--retain-symbols-file,plugin.syms -L$(ronindir)/lib
+MKDIR = mkdir -p
+RM = rm -f
+RM_REC = rm -rf
+AR = arm-eabi-ar cru
+RANLIB = arm-eabi-ranlib
+OBJCOPY = arm-eabi-objcopy
+AS = arm-eabi-as
+HAVE_GCC3 = true
+DISABLE_SCALERS = true
+
+ifdef BUILD_PLUGINS
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+endif
+
+PORT_OBJS :=	$(portdir)/source/blitters.o $(portdir)/source/cdaudio.o $(portdir)/source/dsmain.o \
+		$(portdir)/../../../fs/ds/ds-fs.o $(portdir)/source/gbampsave.o $(portdir)/source/scummhelp.o\
+		$(portdir)/source/osystem_ds.o $(portdir)/source/portdefs.o $(portdir)/source/ramsave.o\
+		$(portdir)/source/scummconsole.o $(portdir)/source/touchkeyboard.o $(portdir)/source/zipreader.o\
+		$(portdir)/source/dsoptions.o
+		
+DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o
+			
+		
+COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o
+
+FAT_OBJS :=  $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o\
+			$(portdir)/source/fat/io_fcsr.o $(portdir)/source/fat/io_m3cf.o\
+			$(portdir)/source/fat/io_mpcf.o $(portdir)/source/fat/io_sccf.o\
+			$(portdir)/source/fat/io_m3sd.o\
+			$(portdir)/source/fat/io_nmmc.o $(portdir)/source/fat/io_scsd.o \
+			$(portdir)/source/fat/io_m3sd_asm.o $(portdir)/source/fat/io_scsd_asm.o 
+			
+			
+			
+OBJS := $(DATA_OBJS) $(PORT_OBJS) $(COMPRESSOR_OBJS) $(FAT_OBJS) 
+		
+
+		
+MODULE_DIRS += .
+
+ndsall:
+	@[ -d $(BUILD) ] || mkdir -p $(BUILD)
+	make -C ./$(BUILD) -f ../makefile scummvm.nds
+
+include $(srcdir)/Makefile.common
+
+clean:
+	$(RM) $(OBJS) $(EXECUTABLE)
+	rm -fr $(BUILD)
+
+plugin_dist :
+	find . -name '*.plg' | while read p; do \
+	  sh-elf-strip -g -o "`basename \"$$p\" | tr '[:lower:]' '[:upper:]'`" "$$p"; \
+	done
+
+dist : SCUMMVM.BIN plugins plugin_dist
+
+
+#---------------------------------------------------------------------------------
+# canned command sequence for binary data
+#---------------------------------------------------------------------------------
+#define bin2o
+#	bin2s $< | $(AS) -mthumb -mthumb-interwork -o $(@)
+#	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_raw_end[];" > `(echo $(<F) | tr . _)`.h
+#	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_raw[];" >> `(echo $(<F) | tr . _)`.h
+#	echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_raw_size";" >> `(echo $(<F) | tr . _)`.h
+#endef
+
+
+define bin2o
+	bin2s $< | $(AS) -mthumb -mthumb-interwork -o $(@)
+	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
+	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
+	echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
+endef
+
+
+#define bin2o
+#	@echo $(*)
+#	cp $(<) $(*).tmp
+#	$(OBJCOPY) -I binary -O elf32-littlearm -B arm \
+#	--rename-section .data=.rodata \
+#	--redefine-sym _binary_$(subst .,_,$(subst /,_,$(*)))_tmp_start=$(notdir $*)\
+#	--redefine-sym _binary_$(subst .,_,$(subst /,_,$(*)))_tmp_end=$(notdir $*)_end\
+#	$(*).tmp $(@)
+#	echo "extern const u8" $(notdir $*)"[] __attribute__ ((aligned (4)));" > $(*).h
+#	echo "extern const u32" $(notdir $(*))_size[]";" >> $(*).h
+#	
+#	echo $(*).h
+#	rm $(*).tmp
+#endef
+
+##############
+# Replacement rule for the one in makefile.common
+##############
+ifndef HAVE_GCC3
+# If you use GCC, disable the above and enable this for intelligent
+# dependency tracking. 
+.cpp.o:
+	$(MKDIR) $(*D)/$(DEPDIR)
+	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
+	$(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d"
+	$(RM) "$(*D)/$(DEPDIR)/$(*F).d2"
+else
+# If you even have GCC 3.x, you can use this build rule, which is safer; the above
+# rule can get you into a bad state if you Ctrl-C at the wrong moment.
+# Also, with this GCC inserts additional dummy rules for the involved headers,
+# which ensures a smooth compilation even if said headers become obsolete.
+.cpp.o:
+	$(MKDIR) $(*D)/$(DEPDIR)
+#	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(CXX) -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d"              $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+endif
+
+
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pcx
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.bin
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.raw
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pal
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.map
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.o	:	%.mdl
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.nds: %.bin
+	@echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6"
+	ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6"
+	dsbuild $@
+	padbin 16 $(basename $@).ds.gba
+
+#---------------------------------------------------------------------------------
+%.bin: %.elf
+	$(OBJCOPY) -S scummvm.elf scummvm-stripped.elf
+	$(OBJCOPY) -O binary scummvm-stripped.elf scummvm.bin
+
+#%.o: %.s
+#	$(MKDIR) $(*D)/$(DEPDIR)
+#	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	
+#BUILD_PLUGINS = 1
+libndsdir = $(DEVKITPRO)/libnds
+
+DS_SCUMM_BUILD = 1
+
+#DS_NON_SCUMM_BUILD = 1
+
+USE_MAD = 1
+
+VPATH = $(srcdir)
+
+# Command to build libmad is:
+# ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork'
+
+ifdef DS_NON_SCUMM_BUILD
+	DEFINES = -DDS_NON_SCUMM_BUILD
+	DISABLE_HE = 1
+	DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	#DISABLE_SIMON = 1
+	#DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	#DISABLE_QUEEN = 1
+	DISABLE_SAGA = 1
+	DISABLE_KYRA = 1
+	#DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	BUILD=scummvm-B
+endif
+
+ifdef DS_SCUMM_BUILD
+	DEFINES = -DDS_SCUMM_BUILD
+	DISABLE_HE = 1
+	#DISABLE_SCUMM = 1
+	DISABLE_SCUMM_7_8 = 1
+	DISABLE_SIMON = 1
+	DISABLE_SKY = 1
+	DISABLE_SWORD1 = 1
+	DISABLE_SWORD2 = 1
+	DISABLE_QUEEN = 1
+	DISABLE_SAGA = 1
+	DISABLE_KYRA = 1
+	DISABLE_GOB = 1
+	DISABLE_LURE = 1
+	DISABLE_CINE = 1
+	DISABLE_AGI = 1
+	BUILD=scummvm-A
+endif
+
+ARM7BIN	:= -7 $(CURDIR)/../../arm7/arm7.bin
+ICON 		:= -b ../../../logo.bmp "ScummVM;By Neil Millstone;"
+
+CC      = arm-eabi-gcc
+CXX     = arm-eabi-g++
+
+CFLAGS	=	-Wno-multichar -Wall -Os\
+		-Wno-multichar -mcpu=arm9tdmi -mtune=arm9tdmi \
+ 		-mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
+		-ffast-math -mthumb-interwork
+		
+CXXFLAGS=	$(CFLAGS) -Wno-non-virtual-dtor	 -Wno-non-virtual-dtor \
+		-fno-exceptions -fno-rtti
+
+ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork
+DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES
+ifdef USE_MAD
+	DEFINES += -DUSE_MAD
+endif
+
+LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt
+
+INCLUDES= -I./ -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/common -I$(portdir)/source -I$(portdir)/source/compressor -I$(portdir)/source/fat \
+			-I$(srcdir)/backends/fs  -I$(srcdir)/backends/fs/ds -I$(portdir)/data -I$(libndsdir)/include -I$(portdir)/../commoninclude\
+			-I$(srcdir)/scumm -I$(libndsdir)/include -I$(libndsdir)/include/nds -I$(srcdir)/engines -I$(portdir)/source/mad
+			
+
+LIBS	= -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9
+ifdef USE_MAD
+	LIBS += -lmad
+endif
+
+#-Lscumm -lscumm -Lbase -lbase -Lcommon -lcommon -Lgraphics -lgraphics -Lgui -lgui -Lsound -lsound
+EXECUTABLE = scummvm.elf
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = plugin.x plugin.syms scummvm.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,-Tplugin.x,--just-symbols,scummvm.elf,--retain-symbols-file,plugin.syms -L$(ronindir)/lib
+MKDIR = mkdir -p
+RM = rm -f
+RM_REC = rm -rf
+AR = arm-eabi-ar cru
+RANLIB = arm-eabi-ranlib
+OBJCOPY = arm-eabi-objcopy
+AS = arm-eabi-as
+HAVE_GCC3 = true
+DISABLE_SCALERS = true
+
+ifdef BUILD_PLUGINS
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+endif
+
+PORT_OBJS :=	$(portdir)/source/blitters.o $(portdir)/source/cdaudio.o $(portdir)/source/dsmain.o \
+		$(portdir)/../../../fs/ds/ds-fs.o $(portdir)/source/gbampsave.o $(portdir)/source/scummhelp.o\
+		$(portdir)/source/osystem_ds.o $(portdir)/source/portdefs.o $(portdir)/source/ramsave.o\
+		$(portdir)/source/scummconsole.o $(portdir)/source/touchkeyboard.o $(portdir)/source/zipreader.o\
+		$(portdir)/source/dsoptions.o
+		
+DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o
+			
+		
+COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o
+
+FAT_OBJS :=  $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o\
+			$(portdir)/source/fat/io_fcsr.o $(portdir)/source/fat/io_m3cf.o\
+			$(portdir)/source/fat/io_mpcf.o $(portdir)/source/fat/io_sccf.o\
+			$(portdir)/source/fat/io_m3sd.o\
+			$(portdir)/source/fat/io_nmmc.o $(portdir)/source/fat/io_scsd.o \
+			$(portdir)/source/fat/io_m3sd_asm.o $(portdir)/source/fat/io_scsd_asm.o 
+			
+			
+			
+OBJS := $(DATA_OBJS) $(PORT_OBJS) $(COMPRESSOR_OBJS) $(FAT_OBJS) 
+		
+
+		
+MODULE_DIRS += .
+
+ndsall:
+	@[ -d $(BUILD) ] || mkdir -p $(BUILD)
+	make -C ./$(BUILD) -f ../makefile scummvm.nds
+
+include $(srcdir)/Makefile.common
+
+clean:
+	$(RM) $(OBJS) $(EXECUTABLE)
+	rm -fr $(BUILD)
+
+plugin_dist :
+	find . -name '*.plg' | while read p; do \
+	  sh-elf-strip -g -o "`basename \"$$p\" | tr '[:lower:]' '[:upper:]'`" "$$p"; \
+	done
+
+dist : SCUMMVM.BIN plugins plugin_dist
+
+
+#---------------------------------------------------------------------------------
+# canned command sequence for binary data
+#---------------------------------------------------------------------------------
+#define bin2o
+#	bin2s $< | $(AS) -mthumb -mthumb-interwork -o $(@)
+#	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_raw_end[];" > `(echo $(<F) | tr . _)`.h
+#	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_raw[];" >> `(echo $(<F) | tr . _)`.h
+#	echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_raw_size";" >> `(echo $(<F) | tr . _)`.h
+#endef
+
+
+define bin2o
+	bin2s $< | $(AS) -mthumb -mthumb-interwork -o $(@)
+	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
+	echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
+	echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
+endef
+
+
+#define bin2o
+#	@echo $(*)
+#	cp $(<) $(*).tmp
+#	$(OBJCOPY) -I binary -O elf32-littlearm -B arm \
+#	--rename-section .data=.rodata \
+#	--redefine-sym _binary_$(subst .,_,$(subst /,_,$(*)))_tmp_start=$(notdir $*)\
+#	--redefine-sym _binary_$(subst .,_,$(subst /,_,$(*)))_tmp_end=$(notdir $*)_end\
+#	$(*).tmp $(@)
+#	echo "extern const u8" $(notdir $*)"[] __attribute__ ((aligned (4)));" > $(*).h
+#	echo "extern const u32" $(notdir $(*))_size[]";" >> $(*).h
+#	
+#	echo $(*).h
+#	rm $(*).tmp
+#endef
+
+##############
+# Replacement rule for the one in makefile.common
+##############
+ifndef HAVE_GCC3
+# If you use GCC, disable the above and enable this for intelligent
+# dependency tracking. 
+.cpp.o:
+	$(MKDIR) $(*D)/$(DEPDIR)
+	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
+	$(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d"
+	$(RM) "$(*D)/$(DEPDIR)/$(*F).d2"
+else
+# If you even have GCC 3.x, you can use this build rule, which is safer; the above
+# rule can get you into a bad state if you Ctrl-C at the wrong moment.
+# Also, with this GCC inserts additional dummy rules for the involved headers,
+# which ensures a smooth compilation even if said headers become obsolete.
+.cpp.o:
+	$(MKDIR) $(*D)/$(DEPDIR)
+#	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	$(CXX) -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d"              $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+endif
+
+
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pcx
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.bin
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.raw
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.pal
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+ 
+#---------------------------------------------------------------------------------
+%.o	:	%.map
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.o	:	%.mdl
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+#---------------------------------------------------------------------------------
+%.nds: %.bin
+	@echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6"
+	ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6"
+	dsbuild $@
+	padbin 16 $(basename $@).ds.gba
+
+#---------------------------------------------------------------------------------
+%.bin: %.elf
+	$(OBJCOPY) -S scummvm.elf scummvm-stripped.elf
+	$(OBJCOPY) -O binary scummvm-stripped.elf scummvm.bin
+
+#%.o: %.s
+#	$(MKDIR) $(*D)/$(DEPDIR)
+#	$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+	
\ No newline at end of file

Added: scummvm/trunk/backends/platform/ds/arm9/source/blitters.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/blitters.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/blitters.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,272 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "stdafx.h"
+#define CHARSET_MASK_TRANSPARENCY 253
+
+namespace DS {
+
+void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
+	int vsPitch, int vmScreenWidth, int textSurfacePitch) {
+
+
+	if (height <= 0) height = 1;
+	if (width < 4) return;
+	
+	
+	width &= ~4;
+//	src = (const byte *) (((int) (src)) & (~4));
+//	dst = (byte *) (((int) (dst)) & (~4));
+//	text = (const byte *) (((int) (text)) & (~4));
+	
+	asm (	"mov r5, %0\n"				// Height
+			"yLoop:\n"			
+			"mov r3, #0\n"				// X pos
+			
+			"xLoop:\n"
+			
+			"ldr r4, [%2, r3]\n"		// Load text layer word
+			"cmp r4, %5\n"
+			"bne singleByteCompare\n"
+			"ldr r4, [%3, r3]\n"
+			"str r4, [%4, r3]\n"
+			"add r3, r3, #4\n"
+			"cmp r3, %1\n"				// x == width?
+			"blt xLoop\n"
+			
+			"add %2, %2, %8\n"			// src += vs->pitch
+			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
+			"add %4, %4, %7\n"			// text += _textSurface.pitch
+			"sub r5, r5, #1\n"			// y -= 1
+			"cmp r5, #0\n"				// y == 0?
+			"bne yLoop\n"
+			"b end\n"
+			
+			
+			"singleByteCompare:\n"
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+			
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"			
+
+			"cmps r3, %1\n"				// x == width?
+			"blt xLoop\n"				// Repeat
+			"add %2, %2, %8\n"			// src += vs->pitch
+			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
+			"add %4, %4, %7\n"			// text += _textSurface.pitch
+			"sub r5, r5, #1\n"			// y -= 1
+			"cmp r5, #0\n"				// y == 0?
+			"bne yLoop\n"
+			
+			"end:\n"
+		: /* no output registers */
+		: "r" (height), "r" (width), "r" (text), "r" (src), "r" (dst), "r" (CHARSET_MASK_TRANSPARENCY | (CHARSET_MASK_TRANSPARENCY << 8) | (CHARSET_MASK_TRANSPARENCY << 16) | (CHARSET_MASK_TRANSPARENCY << 24)), 
+			"r" (vsPitch), "r" (vmScreenWidth), "r" (textSurfacePitch)
+		: "r5", "r3", "r4", "%2", "%3", "%4", "memory");
+}
+
+
+
+void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height) {
+	asm("ands r0, %3, #1\n"
+		 "addne %3, %3, #1\n"
+		 "bne roll2\n"
+			
+		 "yLoop2:\n"
+		 "ldr r0, [%2, #0]\n"
+		 "str r0, [%0, #0]\n"
+		 "ldr r0, [%2, #4]\n"
+		 "str r0, [%0, #4]\n"
+		 "add %0, %0, %1\n"
+		 "add %2, %2, %1\n"
+		 "roll2:\n"
+		 "ldr r0, [%2, #0]\n"
+		 "str r0, [%0, #0]\n"
+		 "ldr r0, [%2, #4]\n"
+		 "str r0, [%0, #4]\n"
+		 "add %0, %0, %1\n"
+		 "add %2, %2, %1\n"
+		 "subs %3, %3, #2\n"
+		 "bne yLoop2\n"		 
+
+		: /* no output registers */
+		: "r" (dst), "r" (dstPitch), "r" (src), "r" (height)
+		: "r0", "%0", "%2", "%3");
+}
+
+}
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "stdafx.h"
+#define CHARSET_MASK_TRANSPARENCY 253
+
+namespace DS {
+
+void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
+	int vsPitch, int vmScreenWidth, int textSurfacePitch) {
+
+
+	if (height <= 0) height = 1;
+	if (width < 4) return;
+	
+	
+	width &= ~4;
+//	src = (const byte *) (((int) (src)) & (~4));
+//	dst = (byte *) (((int) (dst)) & (~4));
+//	text = (const byte *) (((int) (text)) & (~4));
+	
+	asm (	"mov r5, %0\n"				// Height
+			"yLoop:\n"			
+			"mov r3, #0\n"				// X pos
+			
+			"xLoop:\n"
+			
+			"ldr r4, [%2, r3]\n"		// Load text layer word
+			"cmp r4, %5\n"
+			"bne singleByteCompare\n"
+			"ldr r4, [%3, r3]\n"
+			"str r4, [%4, r3]\n"
+			"add r3, r3, #4\n"
+			"cmp r3, %1\n"				// x == width?
+			"blt xLoop\n"
+			
+			"add %2, %2, %8\n"			// src += vs->pitch
+			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
+			"add %4, %4, %7\n"			// text += _textSurface.pitch
+			"sub r5, r5, #1\n"			// y -= 1
+			"cmp r5, #0\n"				// y == 0?
+			"bne yLoop\n"
+			"b end\n"
+			
+			
+			"singleByteCompare:\n"
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+			
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"
+
+			"ldrb r4, [%2, r3]\n"		// Load text byte
+			"cmps r4, %5, lsr #24\n"	// Compare with mask
+			"strneb r4, [%4, r3]\n"		// Store if not equal
+			"ldreqb r4, [%3, r3]\n"		// Otherwise Load src byte
+			"streqb r4, [%4, r3]\n"		// Store it
+			"add r3, r3, #1\n"			
+
+			"cmps r3, %1\n"				// x == width?
+			"blt xLoop\n"				// Repeat
+			"add %2, %2, %8\n"			// src += vs->pitch
+			"add %3, %3, %6\n"			// dst += _vm->_screenWidth
+			"add %4, %4, %7\n"			// text += _textSurface.pitch
+			"sub r5, r5, #1\n"			// y -= 1
+			"cmp r5, #0\n"				// y == 0?
+			"bne yLoop\n"
+			
+			"end:\n"
+		: /* no output registers */
+		: "r" (height), "r" (width), "r" (text), "r" (src), "r" (dst), "r" (CHARSET_MASK_TRANSPARENCY | (CHARSET_MASK_TRANSPARENCY << 8) | (CHARSET_MASK_TRANSPARENCY << 16) | (CHARSET_MASK_TRANSPARENCY << 24)), 
+			"r" (vsPitch), "r" (vmScreenWidth), "r" (textSurfacePitch)
+		: "r5", "r3", "r4", "%2", "%3", "%4", "memory");
+}
+
+
+
+void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height) {
+	asm("ands r0, %3, #1\n"
+		 "addne %3, %3, #1\n"
+		 "bne roll2\n"
+			
+		 "yLoop2:\n"
+		 "ldr r0, [%2, #0]\n"
+		 "str r0, [%0, #0]\n"
+		 "ldr r0, [%2, #4]\n"
+		 "str r0, [%0, #4]\n"
+		 "add %0, %0, %1\n"
+		 "add %2, %2, %1\n"
+		 "roll2:\n"
+		 "ldr r0, [%2, #0]\n"
+		 "str r0, [%0, #0]\n"
+		 "ldr r0, [%2, #4]\n"
+		 "str r0, [%0, #4]\n"
+		 "add %0, %0, %1\n"
+		 "add %2, %2, %1\n"
+		 "subs %3, %3, #2\n"
+		 "bne yLoop2\n"		 
+
+		: /* no output registers */
+		: "r" (dst), "r" (dstPitch), "r" (src), "r" (height)
+		: "r0", "%0", "%2", "%3");
+}
+
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/blitters.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/blitters.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/blitters.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/blitters.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,62 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ #ifndef _BLITTERS_H_
+ #define _BLITTERS_H_
+
+namespace DS {
+
+void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
+	int vsPitch, int vmScreenWidth, int textSurfacePitch);
+void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height);
+
+}
+	
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ #ifndef _BLITTERS_H_
+ #define _BLITTERS_H_
+
+namespace DS {
+
+void asmDrawStripToScreen(int height, int width, byte const* text, byte const* src, byte* dst, 
+	int vsPitch, int vmScreenWidth, int textSurfacePitch);
+void asmCopy8Col(byte* dst, int dstPitch, const byte* src, int height);
+
+}
+	
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/blitters.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,968 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "stdafx.h"
+#include "cdaudio.h"
+#include "ds-fs.h"
+#include "config-manager.h"
+#include "dsmain.h"
+#include "nds/scummvm_ipc.h"
+#include "console2.h"
+
+#define WAV_FORMAT_IMA_ADPCM 0x14
+#define BUFFER_SIZE 8192
+#define BUFFER_CHUNK_SIZE (BUFFER_SIZE >> 2)
+
+namespace DS {
+namespace CD {
+
+struct WaveHeader {
+
+	char		riff[4];		// 'RIFF'
+	u32			size;			// Size of the file
+	char		wave[4];		// 'WAVE'
+
+	// fmt chunk
+	char		fmt[4];			// 'fmt '
+	u32			fmtSize;		// Chunk size
+	u16			fmtFormatTag;	// Format of this file
+	u16			fmtChannels;	// Num channels
+	u32			fmtSamPerSec;	// Samples per second
+	u32			fmtBytesPerSec; // Bytes per second
+	u16			fmtBlockAlign;	// Block alignment
+	u16			fmtBitsPerSam;	// Bits per sample
+
+	u16			fmtExtraData;	// Number of extra fmt bytes
+	u16			fmtExtra;		// Samples per block (only for IMA-ADPCM files)
+} __attribute__ ((packed));
+	
+struct chunkHeader {
+	char 		name[4];	
+	u32			size;
+} __attribute__ ((packed));
+
+struct Header {
+	s16 		firstSample;
+	char		stepTableIndex;
+	char		reserved;
+} __attribute__ ((packed));
+
+struct decoderFormat {
+	s16 initial;
+	unsigned char tableIndex;
+	unsigned char test;
+	unsigned char	sample[1024];
+} __attribute__ ((packed));
+
+bool active = false;
+WaveHeader waveHeader;
+Header blockHeader;
+FILE* file;
+int fillPos;
+bool isPlayingFlag = false;
+
+s16* audioBuffer;
+u32 sampleNum;
+s16* decompressionBuffer;
+int numLoops;
+int blockCount;
+int dataChunkStart;
+int blocksLeft;
+
+
+// These are from Microsoft's document on DVI ADPCM
+const int stepTab[ 89 ] = {
+7, 8, 9, 10, 11, 12, 13, 14,
+16, 17, 19, 21, 23, 25, 28, 31,
+34, 37, 41, 45, 50, 55, 60, 66,
+73, 80, 88, 97, 107, 118, 130, 143,
+157, 173, 190, 209, 230, 253, 279, 307,
+337, 371, 408, 449, 494, 544, 598, 658,
+724, 796, 876, 963, 1060, 1166, 1282, 1411,
+1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+32767 };
+
+const int indexTab[ 16 ] = { -1, -1, -1, -1, 2, 4, 6, 8,
+-1, -1, -1, -1, 2, 4, 6, 8 };
+
+void playNextBlock();
+void decompressBlock();
+
+
+void allocBuffers() {
+	
+}
+
+void setActive(bool active) {
+	active = active;
+}
+
+bool getActive() {
+	return active;
+}
+
+void playTrack(int track, int numLoops, int startFrame, int duration) {
+	Common::String path = ConfMan.get("path");
+	
+	if (isPlayingFlag) {
+		stopTrack();
+	}
+	
+	
+	
+	
+	
+	char str[100];
+	sprintf(str, "/track%d.wav", track);
+	path = path + str;
+	
+	
+	//1820160
+	
+	file = DS::std_fopen(path.c_str(), "rb");
+	
+	if (!file) {
+		consolePrintf("Failed to open %s!\n", path.c_str());
+		return;
+	}
+	
+	
+	DS::std_fread((const void *) &waveHeader, sizeof(waveHeader), 1, file);
+	
+	consolePrintf("Playing track %d\n", track);
+	consolePrintf("Format: %d\n", waveHeader.fmtFormatTag);
+	consolePrintf("Rate  : %d\n", waveHeader.fmtSamPerSec);
+	consolePrintf("Bits  : %d\n", waveHeader.fmtBitsPerSam);
+	consolePrintf("BlkSz : %d\n", waveHeader.fmtExtra);
+	
+	if ((waveHeader.fmtFormatTag != 17) && (waveHeader.fmtFormatTag != 20)) {
+		consolePrintf("Wave file is in the wrong format!  You must use IMA-ADPCM 4-bit mono.\n");
+		return;
+	}
+	
+	for (int r = 0; r < 8; r++) {
+		IPC->adpcm.buffer[r] = (u8 * volatile) (decoderFormat *) malloc(waveHeader.fmtBlockAlign);
+		IPC->adpcm.filled[r] = false;
+		IPC->adpcm.arm7Dirty[r] = false;
+	}
+	
+	// Skip chunks until we reach the data chunk
+	chunkHeader chunk;
+	DS::std_fread((const void *) &chunk, sizeof(chunkHeader), 1, file);
+	
+	while (!((chunk.name[0] == 'd') && (chunk.name[1] == 'a') && (chunk.name[2] == 't') && (chunk.name[3] == 'a'))) {
+		DS::std_fseek(file, chunk.size, SEEK_CUR);
+		DS::std_fread((const void *) &chunk, sizeof(chunkHeader), 1, file);
+	}
+	
+	dataChunkStart = DS::std_ftell(file);
+	
+	
+	static bool started = false;
+	sampleNum = 0;
+	blockCount = 0;
+
+	IPC->streamFillNeeded[0] = true;
+	IPC->streamFillNeeded[1] = true;
+	IPC->streamFillNeeded[2] = true;
+	IPC->streamFillNeeded[3] = true;
+	if (!started) {
+		fillPos = 0;
+		audioBuffer = (s16 *) malloc(BUFFER_SIZE * 2);
+		decompressionBuffer = (s16 *) malloc(waveHeader.fmtExtra * 2);
+		started = true;
+//		consolePrintf("****Starting buffer*****\n");
+		memset(audioBuffer, 0, BUFFER_SIZE * 2);
+		memset(decompressionBuffer, 0, waveHeader.fmtExtra * 2);
+		DS::playSound(audioBuffer, BUFFER_SIZE * 2, false, false, waveHeader.fmtSamPerSec);
+		
+	}	
+	fillPos = (IPC->streamPlayingSection + 1) & 3;
+	isPlayingFlag = true;
+	
+	
+	// Startframe is a 75Hz timer.  Dunno why, since nothing else
+	// seems to run at that rate.
+	int tenths = (startFrame * 10) / 75;
+	
+	// Seek to the nearest block start to the start time
+	int samples = (tenths * waveHeader.fmtSamPerSec) / 10;
+	int block = samples / waveHeader.fmtExtra;
+	
+	
+	if (duration == 0) {
+		blocksLeft = 0;
+	} else {
+		blocksLeft = ((((duration * 100) / 75) * (waveHeader.fmtSamPerSec)) / (waveHeader.fmtExtra) / 100) + 10;
+	}
+//	consolePrintf("Playing %d blocks (%d)\n\n", blocksLeft, duration);
+	
+	// No need to seek if we're starting from the beginning
+	if (block != 0) {
+		DS::std_fseek(file, dataChunkStart + block * waveHeader.fmtBlockAlign, SEEK_SET);
+//		consolePrintf("Startframe: %d  msec: %d (%d,%d)\n", startFrame, tenthssec, samples, block);
+	}
+	
+	
+	//decompressBlock();
+	playNextBlock();
+	numLoops = numLoops;
+}
+
+void update() {
+	playNextBlock();
+}
+
+void decompressBlock() {
+	int block[2048];
+	bool loop = false;
+	
+	blockCount++;
+	
+	if (blockCount < 10) return;
+	
+	
+	do {
+		DS::std_fread((const void *) &blockHeader, sizeof(blockHeader), 1, file);
+	
+		DS::std_fread(&block[0], waveHeader.fmtBlockAlign - sizeof(blockHeader), 1, file);
+
+		if (DS::std_feof(file) ) {
+			// Reached end of file, so loop
+			
+			
+			if ((numLoops == -1) || (numLoops > 1)) {
+				// Seek file to first packet
+				if (numLoops != -1) {
+					numLoops--;
+				}
+				DS::std_fseek(file, dataChunkStart, SEEK_SET);
+				loop = true;
+			} else {
+				// Fill decompression buffer with zeros to prevent glitching
+				for (int r = 0; r < waveHeader.fmtExtra; r++) {
+					decompressionBuffer[r] = 0;
+				}
+//				consolePrintf("Stopping music\n");
+				stopTrack();
+				return;
+			}
+			
+		} else {
+			loop = false;
+		}
+		
+	} while (loop);
+		
+		
+	if (blocksLeft > 0) {
+		blocksLeft--;
+	//	consolePrintf("%d ", blocksLeft);
+		if (blocksLeft == 0) {
+			stopTrack();
+			return;
+		}
+	}
+		
+	// First sample is in header
+	decompressionBuffer[0] = blockHeader.firstSample;
+	
+	// Set up initial table indeces
+	int stepTableIndex = blockHeader.stepTableIndex;
+	int prevSample = blockHeader.firstSample;
+	
+//	consolePrintf("Decompressing block step=%d fs=%d\n", stepTableIndex, prevSample);
+
+	for (int r = 0; r < waveHeader.fmtExtra - 1; r++) {
+		
+		int word = block[r >> 3];
+		int offset = 0;
+		
+		switch (7 - (r & 0x0007)) {
+			case 0: {
+				offset = (word & 0xF0000000) >> 28;
+				break;
+			}
+			
+			case 1: {
+				offset = (word & 0x0F000000) >> 24;
+				break;
+			}
+			
+			case 2: {
+				offset = (word & 0x00F00000) >> 20;
+				break;
+			}
+			
+			case 3: {
+				offset = (word & 0x000F0000) >> 16;
+				break;
+			}
+
+			case 4: {
+				offset = (word & 0x0000F000) >> 12;
+				break;
+			}
+
+			case 5: {
+				offset = (word & 0x00000F00) >> 8;
+				break;
+			}
+
+			case 6: {
+				offset = (word & 0x000000F0) >> 4;
+				break;
+			}
+
+			case 7: {
+				offset = (word & 0x0000000F);
+				break;
+			}
+		}
+		
+		int diff = 0;
+		
+		if (offset & 4) {
+			diff = diff + stepTab[stepTableIndex];
+		}
+		
+		if (offset & 2) {
+			diff = diff + (stepTab[stepTableIndex] >> 1);
+		}
+		
+		if (offset & 1) {
+			diff = diff + (stepTab[stepTableIndex] >> 2);
+		}
+		
+		diff = diff + (stepTab[stepTableIndex] >> 3);
+		
+		if (offset & 8) {
+			diff = -diff;		
+		}
+		
+		int newSample = prevSample + diff;
+		
+		if (newSample > 32767) newSample = 32767;
+		if (newSample < -32768) newSample = -32768;
+		
+		decompressionBuffer[r + 1] = newSample;
+		
+		prevSample = newSample;
+		
+		stepTableIndex += indexTab[offset];
+		
+		if (stepTableIndex > 88) stepTableIndex = 88;
+		if (stepTableIndex < 0) stepTableIndex = 0;
+		
+
+	}
+}
+
+void playNextBlock() {
+	if (!isPlayingFlag) return;
+	int lastBlockId = -1;
+	
+	while (IPC->adpcm.semaphore);		// Wait for buffer to become free if needed
+	IPC->adpcm.semaphore = true;		// Lock the buffer structure to prevent clashing with the ARM7
+//	DC_FlushAll();
+	
+	//-8644, 25088
+	for (int block = fillPos + 1; block < fillPos + 4; block++) {
+
+		int blockId = block & 3;
+		
+		if (IPC->streamFillNeeded[blockId]) {
+			
+			IPC->streamFillNeeded[blockId] = false;
+//			DC_FlushAll();
+			
+/*			if (!(REG_KEYINPUT & KEY_R)) {
+				//consolePrintf("Align: %d First: %d  Step:%d  Res:%d\n", waveHeader.fmtBlockAlign, blockHeader.firstSample, blockHeader.stepTableIndex, blockHeader.reserved);
+				consolePrintf("Filling buffer %d\n", blockId);
+			}*/
+			for (int r = blockId * BUFFER_CHUNK_SIZE; r < (blockId + 1) * BUFFER_CHUNK_SIZE; r++) {
+				if (isPlayingFlag) {
+					audioBuffer[r] = decompressionBuffer[sampleNum++];
+					if (sampleNum >= waveHeader.fmtExtra) {
+						decompressBlock();
+						sampleNum = 0;
+					}
+				}
+			}
+			
+			lastBlockId = blockId;
+			IPC->streamFillNeeded[blockId] = false;
+//			DC_FlushAll();
+
+		}
+	
+		
+		
+	}
+	
+	
+	
+	if (lastBlockId != -1) {
+		fillPos = lastBlockId;
+/*		if (!(REG_KEYINPUT & KEY_R)) {
+			consolePrintf("Frame fill done\n");
+		}*/
+	}
+	IPC->adpcm.semaphore = false;		// Release the buffer structure
+//	DC_FlushAll();
+}
+
+void stopTrack() {
+	if (!isPlayingFlag) return;
+
+	DS::std_fclose(file);
+	
+	isPlayingFlag = false;
+	
+	for (int r = 0; r < BUFFER_SIZE; r++) {
+		audioBuffer[r] = 0;
+	}
+	
+	for (int r= 0; r < waveHeader.fmtExtra; r++) {
+		decompressionBuffer[r] = 0;
+	}
+//	DS::stopSound(1);
+	
+//	free(audioBuffer);
+//	free(decompressionBuffer);
+
+	DC_FlushAll();
+}
+
+bool checkCD() {
+	// Need to check whethe CD audio files are present - do this by trying to open Track1.wav.
+	consolePrintf("Attempted to open cd drive\n");
+
+	Common::String path = ConfMan.get("path");
+	path = path + "/track2.wav";
+	// 6577 153 154
+	consolePrintf("Looking for %s...", path.c_str());
+	
+	FILE* file;
+	if ((file = DS::std_fopen(path.c_str(), "r"))) {
+		consolePrintf("Success!\n");
+		setActive(true);
+		DS::std_fclose(file);
+		return true;
+	} else {
+		setActive(false);
+		consolePrintf("Failed!\n");
+		return false;
+	}
+}
+
+bool isPlaying() {
+	return isPlayingFlag;
+}
+
+}
+}
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "stdafx.h"
+#include "cdaudio.h"
+#include "ds-fs.h"
+#include "config-manager.h"
+#include "dsmain.h"
+#include "nds/scummvm_ipc.h"
+#include "console2.h"
+
+#define WAV_FORMAT_IMA_ADPCM 0x14
+#define BUFFER_SIZE 8192
+#define BUFFER_CHUNK_SIZE (BUFFER_SIZE >> 2)
+
+namespace DS {
+namespace CD {
+
+struct WaveHeader {
+
+	char		riff[4];		// 'RIFF'
+	u32			size;			// Size of the file
+	char		wave[4];		// 'WAVE'
+
+	// fmt chunk
+	char		fmt[4];			// 'fmt '
+	u32			fmtSize;		// Chunk size
+	u16			fmtFormatTag;	// Format of this file
+	u16			fmtChannels;	// Num channels
+	u32			fmtSamPerSec;	// Samples per second
+	u32			fmtBytesPerSec; // Bytes per second
+	u16			fmtBlockAlign;	// Block alignment
+	u16			fmtBitsPerSam;	// Bits per sample
+
+	u16			fmtExtraData;	// Number of extra fmt bytes
+	u16			fmtExtra;		// Samples per block (only for IMA-ADPCM files)
+} __attribute__ ((packed));
+	
+struct chunkHeader {
+	char 		name[4];	
+	u32			size;
+} __attribute__ ((packed));
+
+struct Header {
+	s16 		firstSample;
+	char		stepTableIndex;
+	char		reserved;
+} __attribute__ ((packed));
+
+struct decoderFormat {
+	s16 initial;
+	unsigned char tableIndex;
+	unsigned char test;
+	unsigned char	sample[1024];
+} __attribute__ ((packed));
+
+bool active = false;
+WaveHeader waveHeader;
+Header blockHeader;
+FILE* file;
+int fillPos;
+bool isPlayingFlag = false;
+
+s16* audioBuffer;
+u32 sampleNum;
+s16* decompressionBuffer;
+int numLoops;
+int blockCount;
+int dataChunkStart;
+int blocksLeft;
+
+
+// These are from Microsoft's document on DVI ADPCM
+const int stepTab[ 89 ] = {
+7, 8, 9, 10, 11, 12, 13, 14,
+16, 17, 19, 21, 23, 25, 28, 31,
+34, 37, 41, 45, 50, 55, 60, 66,
+73, 80, 88, 97, 107, 118, 130, 143,
+157, 173, 190, 209, 230, 253, 279, 307,
+337, 371, 408, 449, 494, 544, 598, 658,
+724, 796, 876, 963, 1060, 1166, 1282, 1411,
+1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+32767 };
+
+const int indexTab[ 16 ] = { -1, -1, -1, -1, 2, 4, 6, 8,
+-1, -1, -1, -1, 2, 4, 6, 8 };
+
+void playNextBlock();
+void decompressBlock();
+
+
+void allocBuffers() {
+	
+}
+
+void setActive(bool active) {
+	active = active;
+}
+
+bool getActive() {
+	return active;
+}
+
+void playTrack(int track, int numLoops, int startFrame, int duration) {
+	Common::String path = ConfMan.get("path");
+	
+	if (isPlayingFlag) {
+		stopTrack();
+	}
+	
+	
+	
+	
+	
+	char str[100];
+	sprintf(str, "/track%d.wav", track);
+	path = path + str;
+	
+	
+	//1820160
+	
+	file = DS::std_fopen(path.c_str(), "rb");
+	
+	if (!file) {
+		consolePrintf("Failed to open %s!\n", path.c_str());
+		return;
+	}
+	
+	
+	DS::std_fread((const void *) &waveHeader, sizeof(waveHeader), 1, file);
+	
+	consolePrintf("Playing track %d\n", track);
+	consolePrintf("Format: %d\n", waveHeader.fmtFormatTag);
+	consolePrintf("Rate  : %d\n", waveHeader.fmtSamPerSec);
+	consolePrintf("Bits  : %d\n", waveHeader.fmtBitsPerSam);
+	consolePrintf("BlkSz : %d\n", waveHeader.fmtExtra);
+	
+	if ((waveHeader.fmtFormatTag != 17) && (waveHeader.fmtFormatTag != 20)) {
+		consolePrintf("Wave file is in the wrong format!  You must use IMA-ADPCM 4-bit mono.\n");
+		return;
+	}
+	
+	for (int r = 0; r < 8; r++) {
+		IPC->adpcm.buffer[r] = (u8 * volatile) (decoderFormat *) malloc(waveHeader.fmtBlockAlign);
+		IPC->adpcm.filled[r] = false;
+		IPC->adpcm.arm7Dirty[r] = false;
+	}
+	
+	// Skip chunks until we reach the data chunk
+	chunkHeader chunk;
+	DS::std_fread((const void *) &chunk, sizeof(chunkHeader), 1, file);
+	
+	while (!((chunk.name[0] == 'd') && (chunk.name[1] == 'a') && (chunk.name[2] == 't') && (chunk.name[3] == 'a'))) {
+		DS::std_fseek(file, chunk.size, SEEK_CUR);
+		DS::std_fread((const void *) &chunk, sizeof(chunkHeader), 1, file);
+	}
+	
+	dataChunkStart = DS::std_ftell(file);
+	
+	
+	static bool started = false;
+	sampleNum = 0;
+	blockCount = 0;
+
+	IPC->streamFillNeeded[0] = true;
+	IPC->streamFillNeeded[1] = true;
+	IPC->streamFillNeeded[2] = true;
+	IPC->streamFillNeeded[3] = true;
+	if (!started) {
+		fillPos = 0;
+		audioBuffer = (s16 *) malloc(BUFFER_SIZE * 2);
+		decompressionBuffer = (s16 *) malloc(waveHeader.fmtExtra * 2);
+		started = true;
+//		consolePrintf("****Starting buffer*****\n");
+		memset(audioBuffer, 0, BUFFER_SIZE * 2);
+		memset(decompressionBuffer, 0, waveHeader.fmtExtra * 2);
+		DS::playSound(audioBuffer, BUFFER_SIZE * 2, false, false, waveHeader.fmtSamPerSec);
+		
+	}	
+	fillPos = (IPC->streamPlayingSection + 1) & 3;
+	isPlayingFlag = true;
+	
+	
+	// Startframe is a 75Hz timer.  Dunno why, since nothing else
+	// seems to run at that rate.
+	int tenths = (startFrame * 10) / 75;
+	
+	// Seek to the nearest block start to the start time
+	int samples = (tenths * waveHeader.fmtSamPerSec) / 10;
+	int block = samples / waveHeader.fmtExtra;
+	
+	
+	if (duration == 0) {
+		blocksLeft = 0;
+	} else {
+		blocksLeft = ((((duration * 100) / 75) * (waveHeader.fmtSamPerSec)) / (waveHeader.fmtExtra) / 100) + 10;
+	}
+//	consolePrintf("Playing %d blocks (%d)\n\n", blocksLeft, duration);
+	
+	// No need to seek if we're starting from the beginning
+	if (block != 0) {
+		DS::std_fseek(file, dataChunkStart + block * waveHeader.fmtBlockAlign, SEEK_SET);
+//		consolePrintf("Startframe: %d  msec: %d (%d,%d)\n", startFrame, tenthssec, samples, block);
+	}
+	
+	
+	//decompressBlock();
+	playNextBlock();
+	numLoops = numLoops;
+}
+
+void update() {
+	playNextBlock();
+}
+
+void decompressBlock() {
+	int block[2048];
+	bool loop = false;
+	
+	blockCount++;
+	
+	if (blockCount < 10) return;
+	
+	
+	do {
+		DS::std_fread((const void *) &blockHeader, sizeof(blockHeader), 1, file);
+	
+		DS::std_fread(&block[0], waveHeader.fmtBlockAlign - sizeof(blockHeader), 1, file);
+
+		if (DS::std_feof(file) ) {
+			// Reached end of file, so loop
+			
+			
+			if ((numLoops == -1) || (numLoops > 1)) {
+				// Seek file to first packet
+				if (numLoops != -1) {
+					numLoops--;
+				}
+				DS::std_fseek(file, dataChunkStart, SEEK_SET);
+				loop = true;
+			} else {
+				// Fill decompression buffer with zeros to prevent glitching
+				for (int r = 0; r < waveHeader.fmtExtra; r++) {
+					decompressionBuffer[r] = 0;
+				}
+//				consolePrintf("Stopping music\n");
+				stopTrack();
+				return;
+			}
+			
+		} else {
+			loop = false;
+		}
+		
+	} while (loop);
+		
+		
+	if (blocksLeft > 0) {
+		blocksLeft--;
+	//	consolePrintf("%d ", blocksLeft);
+		if (blocksLeft == 0) {
+			stopTrack();
+			return;
+		}
+	}
+		
+	// First sample is in header
+	decompressionBuffer[0] = blockHeader.firstSample;
+	
+	// Set up initial table indeces
+	int stepTableIndex = blockHeader.stepTableIndex;
+	int prevSample = blockHeader.firstSample;
+	
+//	consolePrintf("Decompressing block step=%d fs=%d\n", stepTableIndex, prevSample);
+
+	for (int r = 0; r < waveHeader.fmtExtra - 1; r++) {
+		
+		int word = block[r >> 3];
+		int offset = 0;
+		
+		switch (7 - (r & 0x0007)) {
+			case 0: {
+				offset = (word & 0xF0000000) >> 28;
+				break;
+			}
+			
+			case 1: {
+				offset = (word & 0x0F000000) >> 24;
+				break;
+			}
+			
+			case 2: {
+				offset = (word & 0x00F00000) >> 20;
+				break;
+			}
+			
+			case 3: {
+				offset = (word & 0x000F0000) >> 16;
+				break;
+			}
+
+			case 4: {
+				offset = (word & 0x0000F000) >> 12;
+				break;
+			}
+
+			case 5: {
+				offset = (word & 0x00000F00) >> 8;
+				break;
+			}
+
+			case 6: {
+				offset = (word & 0x000000F0) >> 4;
+				break;
+			}
+
+			case 7: {
+				offset = (word & 0x0000000F);
+				break;
+			}
+		}
+		
+		int diff = 0;
+		
+		if (offset & 4) {
+			diff = diff + stepTab[stepTableIndex];
+		}
+		
+		if (offset & 2) {
+			diff = diff + (stepTab[stepTableIndex] >> 1);
+		}
+		
+		if (offset & 1) {
+			diff = diff + (stepTab[stepTableIndex] >> 2);
+		}
+		
+		diff = diff + (stepTab[stepTableIndex] >> 3);
+		
+		if (offset & 8) {
+			diff = -diff;		
+		}
+		
+		int newSample = prevSample + diff;
+		
+		if (newSample > 32767) newSample = 32767;
+		if (newSample < -32768) newSample = -32768;
+		
+		decompressionBuffer[r + 1] = newSample;
+		
+		prevSample = newSample;
+		
+		stepTableIndex += indexTab[offset];
+		
+		if (stepTableIndex > 88) stepTableIndex = 88;
+		if (stepTableIndex < 0) stepTableIndex = 0;
+		
+
+	}
+}
+
+void playNextBlock() {
+	if (!isPlayingFlag) return;
+	int lastBlockId = -1;
+	
+	while (IPC->adpcm.semaphore);		// Wait for buffer to become free if needed
+	IPC->adpcm.semaphore = true;		// Lock the buffer structure to prevent clashing with the ARM7
+//	DC_FlushAll();
+	
+	//-8644, 25088
+	for (int block = fillPos + 1; block < fillPos + 4; block++) {
+
+		int blockId = block & 3;
+		
+		if (IPC->streamFillNeeded[blockId]) {
+			
+			IPC->streamFillNeeded[blockId] = false;
+//			DC_FlushAll();
+			
+/*			if (!(REG_KEYINPUT & KEY_R)) {
+				//consolePrintf("Align: %d First: %d  Step:%d  Res:%d\n", waveHeader.fmtBlockAlign, blockHeader.firstSample, blockHeader.stepTableIndex, blockHeader.reserved);
+				consolePrintf("Filling buffer %d\n", blockId);
+			}*/
+			for (int r = blockId * BUFFER_CHUNK_SIZE; r < (blockId + 1) * BUFFER_CHUNK_SIZE; r++) {
+				if (isPlayingFlag) {
+					audioBuffer[r] = decompressionBuffer[sampleNum++];
+					if (sampleNum >= waveHeader.fmtExtra) {
+						decompressBlock();
+						sampleNum = 0;
+					}
+				}
+			}
+			
+			lastBlockId = blockId;
+			IPC->streamFillNeeded[blockId] = false;
+//			DC_FlushAll();
+
+		}
+	
+		
+		
+	}
+	
+	
+	
+	if (lastBlockId != -1) {
+		fillPos = lastBlockId;
+/*		if (!(REG_KEYINPUT & KEY_R)) {
+			consolePrintf("Frame fill done\n");
+		}*/
+	}
+	IPC->adpcm.semaphore = false;		// Release the buffer structure
+//	DC_FlushAll();
+}
+
+void stopTrack() {
+	if (!isPlayingFlag) return;
+
+	DS::std_fclose(file);
+	
+	isPlayingFlag = false;
+	
+	for (int r = 0; r < BUFFER_SIZE; r++) {
+		audioBuffer[r] = 0;
+	}
+	
+	for (int r= 0; r < waveHeader.fmtExtra; r++) {
+		decompressionBuffer[r] = 0;
+	}
+//	DS::stopSound(1);
+	
+//	free(audioBuffer);
+//	free(decompressionBuffer);
+
+	DC_FlushAll();
+}
+
+bool checkCD() {
+	// Need to check whethe CD audio files are present - do this by trying to open Track1.wav.
+	consolePrintf("Attempted to open cd drive\n");
+
+	Common::String path = ConfMan.get("path");
+	path = path + "/track2.wav";
+	// 6577 153 154
+	consolePrintf("Looking for %s...", path.c_str());
+	
+	FILE* file;
+	if ((file = DS::std_fopen(path.c_str(), "r"))) {
+		consolePrintf("Success!\n");
+		setActive(true);
+		DS::std_fclose(file);
+		return true;
+	} else {
+		setActive(false);
+		consolePrintf("Failed!\n");
+		return false;
+	}
+}
+
+bool isPlaying() {
+	return isPlayingFlag;
+}
+
+}
+}
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,74 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ #ifndef _CDAUDIO_H_
+#define _CDAUDIO_H_
+
+namespace DS {
+namespace CD {
+
+void setActive(bool active);
+void playTrack(int track, int numLoops, int startFrame, int duration);
+void stopTrack();
+bool checkCD();
+bool getActive();
+bool isPlaying();
+void update();
+
+}
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ #ifndef _CDAUDIO_H_
+#define _CDAUDIO_H_
+
+namespace DS {
+namespace CD {
+
+void setActive(bool active);
+void playTrack(int track, int numLoops, int startFrame, int duration);
+void stopTrack();
+bool checkCD();
+bool getActive();
+bool isPlaying();
+void update();
+
+}
+}
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/cdaudio.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,1078 @@
+/*************************************************************************
+* Name:        lz.c
+* Author:      Marcus Geelnard
+* Description: LZ77 coder/decoder implementation.
+* Reentrant:   Yes
+* $Id$
+*
+* The LZ77 compression scheme is a substitutional compression scheme
+* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in
+* its design, and uses no fancy bit level compression.
+*
+* This is my first attempt at an implementation of a LZ77 code/decoder.
+*
+* The principle of the LZ77 compression algorithm is to store repeated
+* occurrences of strings as references to previous occurrences of the same
+* string. The point is that the reference consumes less space than the
+* string itself, provided that the string is long enough (in this
+* implementation, the string has to be at least 4 bytes long, since the
+* minimum coded reference is 3 bytes long). Also note that the term
+* "string" refers to any kind of byte sequence (it does not have to be
+* an ASCII string, for instance).
+*
+* The coder uses a brute force approach to finding string matches in the
+* history buffer (or "sliding window", if you wish), which is very, very
+* slow. I recon the complexity is somewhere between O(n^2) and O(n^3),
+* depending on the input data.
+*
+* There is also a faster implementation that uses a large working buffer
+* in which a "jump table" is stored, which is used to quickly find
+* possible string matches (see the source code for LZ_CompressFast() for
+* more information). The faster method is an order of magnitude faster,
+* and also does a full string search in the entire input buffer (it does
+* not use a sliding window).
+*
+* The upside is that decompression is very fast, and the compression ratio
+* is often very good.
+*
+* The reference to a string is coded as a (length,offset) pair, where the
+* length indicates the length of the string, and the offset gives the
+* offset from the current data position. To distinguish between string
+* references and literal strings (uncompressed bytes), a string reference
+* is preceded by a marker byte, which is chosen as the least common byte
+* symbol in the input data stream (this marker byte is stored in the
+* output stream as the first byte).
+*
+* Occurrences of the marker byte in the stream are encoded as the marker
+* byte followed by a zero byte, which means that occurrences of the marker
+* byte have to be coded with two bytes.
+*
+* The lengths and offsets are coded in a variable length fashion, allowing
+* values of any magnitude (up to 4294967295 in this implementation).
+*
+* With this compression scheme, the worst case compression result is
+* (257/256)*insize + 1.
+*
+*-------------------------------------------------------------------------
+* Copyright (c) 2003-2004 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would
+*    be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not
+*    be misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* Marcus Geelnard
+* marcus.geelnard at home.se
+*************************************************************************/
+
+
+/*************************************************************************
+* Constants used for LZ77 coding
+*************************************************************************/
+
+/* Maximum offset (can be any size < 2^32). Lower values gives faster
+   compression, while higher values gives better compression.
+   NOTE: LZ_CompressFast does not use this constant. */
+#define LZ_MAX_OFFSET 512
+
+
+
+/*************************************************************************
+*                           INTERNAL FUNCTIONS                           *
+*************************************************************************/
+
+
+/*************************************************************************
+* _LZ_StringCompare() - Return maximum length string match.
+*************************************************************************/
+
+inline static unsigned int _LZ_StringCompare( unsigned char * str1,
+  unsigned char * str2, unsigned int minlen, unsigned int maxlen )
+{
+    unsigned int len;
+
+    for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len );
+
+    return len;
+}
+
+
+/*************************************************************************
+* _LZ_WriteVarSize() - Write unsigned integer with variable number of
+* bytes depending on value.
+*************************************************************************/
+
+inline static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf )
+{
+    unsigned int y;
+    int num_bytes, i, b;
+
+    /* Determine number of bytes needed to store the number x */
+    y = x >> 3;
+    for( num_bytes = 5; num_bytes >= 2; -- num_bytes )
+    {
+        if( y & 0xfe000000 ) break;
+        y <<= 7;
+    }
+
+    /* Write all bytes, seven bits in each, with 8:th bit set for all */
+    /* but the last byte. */
+    for( i = num_bytes-1; i >= 0; -- i )
+    {
+        b = (x >> (i*7)) & 0x0000007f;
+        if( i > 0 )
+        {
+            b |= 0x00000080;
+        }
+        *buf ++ = (unsigned char) b;
+    }
+
+    /* Return number of bytes written */
+    return num_bytes;
+}
+
+
+/*************************************************************************
+* _LZ_ReadVarSize() - Read unsigned integer with variable number of
+* bytes depending on value.
+*************************************************************************/
+
+inline static int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf )
+{
+    unsigned int y, b, num_bytes;
+
+    /* Read complete value (stop when byte contains zero in 8:th bit) */
+    y = 0;
+    num_bytes = 0;
+    do
+    {
+        b = (unsigned int) (*buf ++);
+        y = (y << 7) | (b & 0x0000007f);
+        ++ num_bytes;
+    }
+    while( b & 0x00000080 );
+
+    /* Store value in x */
+    *x = y;
+
+    /* Return number of bytes read */
+    return num_bytes;
+}
+
+
+
+/*************************************************************************
+*                            PUBLIC FUNCTIONS                            *
+*************************************************************************/
+
+
+/*************************************************************************
+* LZ_Compress() - Compress a block of data using an LZ77 coder.
+*  in     - Input (uncompressed) buffer.
+*  out    - Output (compressed) buffer. This buffer must be 0.4% larger
+*           than the input buffer, plus one byte.
+*  insize - Number of input bytes.
+* The function returns the size of the compressed data.
+*************************************************************************/
+
+int LZ_Compress( unsigned char *in, unsigned char *out,
+    unsigned int insize )
+{
+    unsigned char marker, symbol;
+    unsigned int  inpos, outpos, bytesleft, i;
+    unsigned int  maxoffset, offset, bestoffset;
+    unsigned int  maxlength, length, bestlength;
+    unsigned int  histogram[ 256 ];
+    unsigned char *ptr1, *ptr2;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return 0;
+    }
+
+    /* Create histogram */
+    for( i = 0; i < 256; ++ i )
+    {
+        histogram[ i ] = 0;
+    }
+    for( i = 0; i < insize; ++ i )
+    {
+        ++ histogram[ in[ i ] ];
+    }
+
+    /* Find the least common byte, and use it as the code marker */
+    marker = 0;
+    for( i = 1; i < 256; ++ i )
+    {
+        if( histogram[ i ] < histogram[ marker ] )
+        {
+            marker = i;
+        }
+    }
+
+    /* Remember the repetition marker for the decoder */
+    out[ 0 ] = marker;
+
+    /* Start of compression */
+    inpos = 0;
+    outpos = 1;
+
+    /* Main compression loop */
+    bytesleft = insize;
+    do
+    {
+        /* Determine most distant position */
+        if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET;
+        else                        maxoffset = inpos;
+
+        /* Get pointer to current position */
+        ptr1 = &in[ inpos ];
+
+        /* Search history window for maximum length string match */
+        bestlength = 3;
+        bestoffset = 0;
+        for( offset = 3; offset <= maxoffset; ++ offset )
+        {
+            /* Get pointer to candidate string */
+            ptr2 = &ptr1[ -offset ];
+
+            /* Quickly determine if this is a candidate (for speed) */
+            if( (ptr1[ 0 ] == ptr2[ 0 ]) &&
+                (ptr1[ bestlength ] == ptr2[ bestlength ]) )
+            {
+                /* Determine maximum length for this offset */
+                maxlength = (bytesleft < offset ? bytesleft : offset);
+
+                /* Count maximum length match at this offset */
+                length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength );
+
+                /* Better match than any previous match? */
+                if( length > bestlength )
+                {
+                    bestlength = length;
+                    bestoffset = offset;
+                }
+            }
+        }
+
+        /* Was there a good enough match? */
+        if( (bestlength >= 8) ||
+            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
+            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
+            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
+            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
+        {
+            out[ outpos ++ ] = (unsigned char) marker;
+            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
+            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
+            inpos += bestlength;
+            bytesleft -= bestlength;
+        }
+        else
+        {
+            /* Output single byte (or two bytes if marker byte) */
+            symbol = in[ inpos ++ ];
+            out[ outpos ++ ] = symbol;
+            if( symbol == marker )
+            {
+                out[ outpos ++ ] = 0;
+            }
+            -- bytesleft;
+        }
+    }
+    while( bytesleft > 3 );
+
+    /* Dump remaining bytes, if any */
+    while( inpos < insize )
+    {
+        if( in[ inpos ] == marker )
+        {
+            out[ outpos ++ ] = marker;
+            out[ outpos ++ ] = 0;
+        }
+        else
+        {
+            out[ outpos ++ ] = in[ inpos ];
+        }
+        ++ inpos;
+    }
+
+    return outpos;
+}
+
+
+/*************************************************************************
+* LZ_CompressFast() - Compress a block of data using an LZ77 coder.
+*  in     - Input (uncompressed) buffer.
+*  out    - Output (compressed) buffer. This buffer must be 0.4% larger
+*           than the input buffer, plus one byte.
+*  insize - Number of input bytes.
+*  work   - Pointer to a temporary buffer (internal working buffer), which
+*           must be able to hold (insize+65536) unsigned integers.
+* The function returns the size of the compressed data.
+*************************************************************************/
+
+int LZ_CompressFast( unsigned char *in, unsigned char *out,
+    unsigned int insize, unsigned int *work )
+{
+    unsigned char marker, symbol;
+    unsigned int  inpos, outpos, bytesleft, i, index, symbols;
+    unsigned int  offset, bestoffset;
+    unsigned int  maxlength, length, bestlength;
+    unsigned int  histogram[ 256 ], *lastindex, *jumptable;
+    unsigned char *ptr1, *ptr2;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return 0;
+    }
+
+    /* Assign arrays to the working area */
+    lastindex = work;
+    jumptable = &work[ 65536 ];
+
+    /* Build a "jump table". Here is how the jump table works:
+       jumptable[i] points to the nearest previous occurrence of the same
+       symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and
+       in[i+1] == in[jumptable[i]+1]. Following the jump table gives a
+       dramatic boost for the string search'n'match loop compared to doing
+       a brute force search. */
+    for( i = 0; i < 65536; ++ i )
+    {
+        lastindex[ i ] = 0xffffffff;
+    }
+    for( i = 0; i < insize-1; ++ i )
+    {
+        symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]);
+        index = lastindex[ symbols ];
+        lastindex[ symbols ] = i;
+        jumptable[ i ] = index;
+    }
+    jumptable[ insize-1 ] = 0xffffffff;
+
+    /* Create histogram */
+    for( i = 0; i < 256; ++ i )
+    {
+        histogram[ i ] = 0;
+    }
+    for( i = 0; i < insize; ++ i )
+    {
+        ++ histogram[ in[ i ] ];
+    }
+
+    /* Find the least common byte, and use it as the code marker */
+    marker = 0;
+    for( i = 1; i < 256; ++ i )
+    {
+        if( histogram[ i ] < histogram[ marker ] )
+        {
+            marker = i;
+        }
+    }
+
+    /* Remember the repetition marker for the decoder */
+    out[ 0 ] = marker;
+
+    /* Start of compression */
+    inpos = 0;
+    outpos = 1;
+
+    /* Main compression loop */
+    bytesleft = insize;
+    do
+    {
+        /* Get pointer to current position */
+        ptr1 = &in[ inpos ];
+
+        /* Search history window for maximum length string match */
+        bestlength = 3;
+        bestoffset = 0;
+        index = jumptable[ inpos ];
+        while( index != 0xffffffff )
+        {
+            /* Get pointer to candidate string */
+            ptr2 = &in[ index ];
+
+            /* Quickly determine if this is a candidate (for speed) */
+            if( ptr2[ bestlength ] == ptr1[ bestlength ] )
+            {
+                /* Determine maximum length for this offset */
+                offset = inpos - index;
+                maxlength = (bytesleft < offset ? bytesleft : offset);
+
+                /* Count maximum length match at this offset */
+                length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength );
+
+                /* Better match than any previous match? */
+                if( length > bestlength )
+                {
+                    bestlength = length;
+                    bestoffset = offset;
+                }
+            }
+
+            /* Get next possible index from jump table */
+            index = jumptable[ index ];
+        }
+
+        /* Was there a good enough match? */
+        if( (bestlength >= 8) ||
+            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
+            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
+            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
+            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
+        {
+            out[ outpos ++ ] = (unsigned char) marker;
+            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
+            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
+            inpos += bestlength;
+            bytesleft -= bestlength;
+        }
+        else
+        {
+            /* Output single byte (or two bytes if marker byte) */
+            symbol = in[ inpos ++ ];
+            out[ outpos ++ ] = symbol;
+            if( symbol == marker )
+            {
+                out[ outpos ++ ] = 0;
+            }
+            -- bytesleft;
+        }
+    }
+    while( bytesleft > 3 );
+
+    /* Dump remaining bytes, if any */
+    while( inpos < insize )
+    {
+        if( in[ inpos ] == marker )
+        {
+            out[ outpos ++ ] = marker;
+            out[ outpos ++ ] = 0;
+        }
+        else
+        {
+            out[ outpos ++ ] = in[ inpos ];
+        }
+        ++ inpos;
+    }
+
+    return outpos;
+}
+
+
+/*************************************************************************
+* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.
+*  in      - Input (compressed) buffer.
+*  out     - Output (uncompressed) buffer. This buffer must be large
+*            enough to hold the uncompressed data.
+*  insize  - Number of input bytes.
+*************************************************************************/
+
+void LZ_Uncompress( unsigned char *in, unsigned char *out,
+    unsigned int insize )
+{
+    unsigned char marker, symbol;
+    unsigned int  i, inpos, outpos, length, offset;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return;
+    }
+
+    /* Get marker symbol from input stream */
+    marker = in[ 0 ];
+    inpos = 1;
+
+    /* Main decompression loop */
+    outpos = 0;
+    do
+    {
+        symbol = in[ inpos ++ ];
+        if( symbol == marker )
+        {
+            /* We had a marker byte */
+            if( in[ inpos ] == 0 )
+            {
+                /* It was a single occurrence of the marker byte */
+                out[ outpos ++ ] = marker;
+                ++ inpos;
+            }
+            else
+            {
+                /* Extract true length and offset */
+                inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );
+                inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );
+
+                /* Copy corresponding data from history window */
+                for( i = 0; i < length; ++ i )
+                {
+                    out[ outpos ] = out[ outpos - offset ];
+                    ++ outpos;
+                }
+            }
+        }
+        else
+        {
+            /* No marker, plain copy */
+            out[ outpos ++ ] = symbol;
+        }
+    }
+    while( inpos < insize );
+}
+/*************************************************************************
+* Name:        lz.c
+* Author:      Marcus Geelnard
+* Description: LZ77 coder/decoder implementation.
+* Reentrant:   Yes
+* $Id$
+*
+* The LZ77 compression scheme is a substitutional compression scheme
+* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in
+* its design, and uses no fancy bit level compression.
+*
+* This is my first attempt at an implementation of a LZ77 code/decoder.
+*
+* The principle of the LZ77 compression algorithm is to store repeated
+* occurrences of strings as references to previous occurrences of the same
+* string. The point is that the reference consumes less space than the
+* string itself, provided that the string is long enough (in this
+* implementation, the string has to be at least 4 bytes long, since the
+* minimum coded reference is 3 bytes long). Also note that the term
+* "string" refers to any kind of byte sequence (it does not have to be
+* an ASCII string, for instance).
+*
+* The coder uses a brute force approach to finding string matches in the
+* history buffer (or "sliding window", if you wish), which is very, very
+* slow. I recon the complexity is somewhere between O(n^2) and O(n^3),
+* depending on the input data.
+*
+* There is also a faster implementation that uses a large working buffer
+* in which a "jump table" is stored, which is used to quickly find
+* possible string matches (see the source code for LZ_CompressFast() for
+* more information). The faster method is an order of magnitude faster,
+* and also does a full string search in the entire input buffer (it does
+* not use a sliding window).
+*
+* The upside is that decompression is very fast, and the compression ratio
+* is often very good.
+*
+* The reference to a string is coded as a (length,offset) pair, where the
+* length indicates the length of the string, and the offset gives the
+* offset from the current data position. To distinguish between string
+* references and literal strings (uncompressed bytes), a string reference
+* is preceded by a marker byte, which is chosen as the least common byte
+* symbol in the input data stream (this marker byte is stored in the
+* output stream as the first byte).
+*
+* Occurrences of the marker byte in the stream are encoded as the marker
+* byte followed by a zero byte, which means that occurrences of the marker
+* byte have to be coded with two bytes.
+*
+* The lengths and offsets are coded in a variable length fashion, allowing
+* values of any magnitude (up to 4294967295 in this implementation).
+*
+* With this compression scheme, the worst case compression result is
+* (257/256)*insize + 1.
+*
+*-------------------------------------------------------------------------
+* Copyright (c) 2003-2004 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would
+*    be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not
+*    be misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* Marcus Geelnard
+* marcus.geelnard at home.se
+*************************************************************************/
+
+
+/*************************************************************************
+* Constants used for LZ77 coding
+*************************************************************************/
+
+/* Maximum offset (can be any size < 2^32). Lower values gives faster
+   compression, while higher values gives better compression.
+   NOTE: LZ_CompressFast does not use this constant. */
+#define LZ_MAX_OFFSET 512
+
+
+
+/*************************************************************************
+*                           INTERNAL FUNCTIONS                           *
+*************************************************************************/
+
+
+/*************************************************************************
+* _LZ_StringCompare() - Return maximum length string match.
+*************************************************************************/
+
+inline static unsigned int _LZ_StringCompare( unsigned char * str1,
+  unsigned char * str2, unsigned int minlen, unsigned int maxlen )
+{
+    unsigned int len;
+
+    for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len );
+
+    return len;
+}
+
+
+/*************************************************************************
+* _LZ_WriteVarSize() - Write unsigned integer with variable number of
+* bytes depending on value.
+*************************************************************************/
+
+inline static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf )
+{
+    unsigned int y;
+    int num_bytes, i, b;
+
+    /* Determine number of bytes needed to store the number x */
+    y = x >> 3;
+    for( num_bytes = 5; num_bytes >= 2; -- num_bytes )
+    {
+        if( y & 0xfe000000 ) break;
+        y <<= 7;
+    }
+
+    /* Write all bytes, seven bits in each, with 8:th bit set for all */
+    /* but the last byte. */
+    for( i = num_bytes-1; i >= 0; -- i )
+    {
+        b = (x >> (i*7)) & 0x0000007f;
+        if( i > 0 )
+        {
+            b |= 0x00000080;
+        }
+        *buf ++ = (unsigned char) b;
+    }
+
+    /* Return number of bytes written */
+    return num_bytes;
+}
+
+
+/*************************************************************************
+* _LZ_ReadVarSize() - Read unsigned integer with variable number of
+* bytes depending on value.
+*************************************************************************/
+
+inline static int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf )
+{
+    unsigned int y, b, num_bytes;
+
+    /* Read complete value (stop when byte contains zero in 8:th bit) */
+    y = 0;
+    num_bytes = 0;
+    do
+    {
+        b = (unsigned int) (*buf ++);
+        y = (y << 7) | (b & 0x0000007f);
+        ++ num_bytes;
+    }
+    while( b & 0x00000080 );
+
+    /* Store value in x */
+    *x = y;
+
+    /* Return number of bytes read */
+    return num_bytes;
+}
+
+
+
+/*************************************************************************
+*                            PUBLIC FUNCTIONS                            *
+*************************************************************************/
+
+
+/*************************************************************************
+* LZ_Compress() - Compress a block of data using an LZ77 coder.
+*  in     - Input (uncompressed) buffer.
+*  out    - Output (compressed) buffer. This buffer must be 0.4% larger
+*           than the input buffer, plus one byte.
+*  insize - Number of input bytes.
+* The function returns the size of the compressed data.
+*************************************************************************/
+
+int LZ_Compress( unsigned char *in, unsigned char *out,
+    unsigned int insize )
+{
+    unsigned char marker, symbol;
+    unsigned int  inpos, outpos, bytesleft, i;
+    unsigned int  maxoffset, offset, bestoffset;
+    unsigned int  maxlength, length, bestlength;
+    unsigned int  histogram[ 256 ];
+    unsigned char *ptr1, *ptr2;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return 0;
+    }
+
+    /* Create histogram */
+    for( i = 0; i < 256; ++ i )
+    {
+        histogram[ i ] = 0;
+    }
+    for( i = 0; i < insize; ++ i )
+    {
+        ++ histogram[ in[ i ] ];
+    }
+
+    /* Find the least common byte, and use it as the code marker */
+    marker = 0;
+    for( i = 1; i < 256; ++ i )
+    {
+        if( histogram[ i ] < histogram[ marker ] )
+        {
+            marker = i;
+        }
+    }
+
+    /* Remember the repetition marker for the decoder */
+    out[ 0 ] = marker;
+
+    /* Start of compression */
+    inpos = 0;
+    outpos = 1;
+
+    /* Main compression loop */
+    bytesleft = insize;
+    do
+    {
+        /* Determine most distant position */
+        if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET;
+        else                        maxoffset = inpos;
+
+        /* Get pointer to current position */
+        ptr1 = &in[ inpos ];
+
+        /* Search history window for maximum length string match */
+        bestlength = 3;
+        bestoffset = 0;
+        for( offset = 3; offset <= maxoffset; ++ offset )
+        {
+            /* Get pointer to candidate string */
+            ptr2 = &ptr1[ -offset ];
+
+            /* Quickly determine if this is a candidate (for speed) */
+            if( (ptr1[ 0 ] == ptr2[ 0 ]) &&
+                (ptr1[ bestlength ] == ptr2[ bestlength ]) )
+            {
+                /* Determine maximum length for this offset */
+                maxlength = (bytesleft < offset ? bytesleft : offset);
+
+                /* Count maximum length match at this offset */
+                length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength );
+
+                /* Better match than any previous match? */
+                if( length > bestlength )
+                {
+                    bestlength = length;
+                    bestoffset = offset;
+                }
+            }
+        }
+
+        /* Was there a good enough match? */
+        if( (bestlength >= 8) ||
+            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
+            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
+            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
+            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
+        {
+            out[ outpos ++ ] = (unsigned char) marker;
+            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
+            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
+            inpos += bestlength;
+            bytesleft -= bestlength;
+        }
+        else
+        {
+            /* Output single byte (or two bytes if marker byte) */
+            symbol = in[ inpos ++ ];
+            out[ outpos ++ ] = symbol;
+            if( symbol == marker )
+            {
+                out[ outpos ++ ] = 0;
+            }
+            -- bytesleft;
+        }
+    }
+    while( bytesleft > 3 );
+
+    /* Dump remaining bytes, if any */
+    while( inpos < insize )
+    {
+        if( in[ inpos ] == marker )
+        {
+            out[ outpos ++ ] = marker;
+            out[ outpos ++ ] = 0;
+        }
+        else
+        {
+            out[ outpos ++ ] = in[ inpos ];
+        }
+        ++ inpos;
+    }
+
+    return outpos;
+}
+
+
+/*************************************************************************
+* LZ_CompressFast() - Compress a block of data using an LZ77 coder.
+*  in     - Input (uncompressed) buffer.
+*  out    - Output (compressed) buffer. This buffer must be 0.4% larger
+*           than the input buffer, plus one byte.
+*  insize - Number of input bytes.
+*  work   - Pointer to a temporary buffer (internal working buffer), which
+*           must be able to hold (insize+65536) unsigned integers.
+* The function returns the size of the compressed data.
+*************************************************************************/
+
+int LZ_CompressFast( unsigned char *in, unsigned char *out,
+    unsigned int insize, unsigned int *work )
+{
+    unsigned char marker, symbol;
+    unsigned int  inpos, outpos, bytesleft, i, index, symbols;
+    unsigned int  offset, bestoffset;
+    unsigned int  maxlength, length, bestlength;
+    unsigned int  histogram[ 256 ], *lastindex, *jumptable;
+    unsigned char *ptr1, *ptr2;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return 0;
+    }
+
+    /* Assign arrays to the working area */
+    lastindex = work;
+    jumptable = &work[ 65536 ];
+
+    /* Build a "jump table". Here is how the jump table works:
+       jumptable[i] points to the nearest previous occurrence of the same
+       symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and
+       in[i+1] == in[jumptable[i]+1]. Following the jump table gives a
+       dramatic boost for the string search'n'match loop compared to doing
+       a brute force search. */
+    for( i = 0; i < 65536; ++ i )
+    {
+        lastindex[ i ] = 0xffffffff;
+    }
+    for( i = 0; i < insize-1; ++ i )
+    {
+        symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]);
+        index = lastindex[ symbols ];
+        lastindex[ symbols ] = i;
+        jumptable[ i ] = index;
+    }
+    jumptable[ insize-1 ] = 0xffffffff;
+
+    /* Create histogram */
+    for( i = 0; i < 256; ++ i )
+    {
+        histogram[ i ] = 0;
+    }
+    for( i = 0; i < insize; ++ i )
+    {
+        ++ histogram[ in[ i ] ];
+    }
+
+    /* Find the least common byte, and use it as the code marker */
+    marker = 0;
+    for( i = 1; i < 256; ++ i )
+    {
+        if( histogram[ i ] < histogram[ marker ] )
+        {
+            marker = i;
+        }
+    }
+
+    /* Remember the repetition marker for the decoder */
+    out[ 0 ] = marker;
+
+    /* Start of compression */
+    inpos = 0;
+    outpos = 1;
+
+    /* Main compression loop */
+    bytesleft = insize;
+    do
+    {
+        /* Get pointer to current position */
+        ptr1 = &in[ inpos ];
+
+        /* Search history window for maximum length string match */
+        bestlength = 3;
+        bestoffset = 0;
+        index = jumptable[ inpos ];
+        while( index != 0xffffffff )
+        {
+            /* Get pointer to candidate string */
+            ptr2 = &in[ index ];
+
+            /* Quickly determine if this is a candidate (for speed) */
+            if( ptr2[ bestlength ] == ptr1[ bestlength ] )
+            {
+                /* Determine maximum length for this offset */
+                offset = inpos - index;
+                maxlength = (bytesleft < offset ? bytesleft : offset);
+
+                /* Count maximum length match at this offset */
+                length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength );
+
+                /* Better match than any previous match? */
+                if( length > bestlength )
+                {
+                    bestlength = length;
+                    bestoffset = offset;
+                }
+            }
+
+            /* Get next possible index from jump table */
+            index = jumptable[ index ];
+        }
+
+        /* Was there a good enough match? */
+        if( (bestlength >= 8) ||
+            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
+            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
+            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
+            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
+        {
+            out[ outpos ++ ] = (unsigned char) marker;
+            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
+            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
+            inpos += bestlength;
+            bytesleft -= bestlength;
+        }
+        else
+        {
+            /* Output single byte (or two bytes if marker byte) */
+            symbol = in[ inpos ++ ];
+            out[ outpos ++ ] = symbol;
+            if( symbol == marker )
+            {
+                out[ outpos ++ ] = 0;
+            }
+            -- bytesleft;
+        }
+    }
+    while( bytesleft > 3 );
+
+    /* Dump remaining bytes, if any */
+    while( inpos < insize )
+    {
+        if( in[ inpos ] == marker )
+        {
+            out[ outpos ++ ] = marker;
+            out[ outpos ++ ] = 0;
+        }
+        else
+        {
+            out[ outpos ++ ] = in[ inpos ];
+        }
+        ++ inpos;
+    }
+
+    return outpos;
+}
+
+
+/*************************************************************************
+* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.
+*  in      - Input (compressed) buffer.
+*  out     - Output (uncompressed) buffer. This buffer must be large
+*            enough to hold the uncompressed data.
+*  insize  - Number of input bytes.
+*************************************************************************/
+
+void LZ_Uncompress( unsigned char *in, unsigned char *out,
+    unsigned int insize )
+{
+    unsigned char marker, symbol;
+    unsigned int  i, inpos, outpos, length, offset;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 )
+    {
+        return;
+    }
+
+    /* Get marker symbol from input stream */
+    marker = in[ 0 ];
+    inpos = 1;
+
+    /* Main decompression loop */
+    outpos = 0;
+    do
+    {
+        symbol = in[ inpos ++ ];
+        if( symbol == marker )
+        {
+            /* We had a marker byte */
+            if( in[ inpos ] == 0 )
+            {
+                /* It was a single occurrence of the marker byte */
+                out[ outpos ++ ] = marker;
+                ++ inpos;
+            }
+            else
+            {
+                /* Extract true length and offset */
+                inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );
+                inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );
+
+                /* Copy corresponding data from history window */
+                for( i = 0; i < length; ++ i )
+                {
+                    out[ outpos ] = out[ outpos - offset ];
+                    ++ outpos;
+                }
+            }
+        }
+        else
+        {
+            /* No marker, plain copy */
+            out[ outpos ++ ] = symbol;
+        }
+    }
+    while( inpos < insize );
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,100 @@
+/*************************************************************************
+* Name:        lz.h
+* Author:      Marcus Geelnard
+* Description: LZ77 coder/decoder interface.
+* Reentrant:   Yes
+* $Id$
+*-------------------------------------------------------------------------
+* Copyright (c) 2003-2004 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would
+*    be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not
+*    be misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* Marcus Geelnard
+* marcus.geelnard at home.se
+*************************************************************************/
+
+#ifndef _lz_h_
+#define _lz_h_
+
+
+
+/*************************************************************************
+* Function prototypes
+*************************************************************************/
+
+int LZ_Compress( unsigned char *in, unsigned char *out,
+                 unsigned int insize );
+int LZ_CompressFast( unsigned char *in, unsigned char *out,
+                     unsigned int insize, unsigned int *work );
+void LZ_Uncompress( unsigned char *in, unsigned char *out,
+                    unsigned int insize );
+
+
+#endif /* _lz_h_ */
+/*************************************************************************
+* Name:        lz.h
+* Author:      Marcus Geelnard
+* Description: LZ77 coder/decoder interface.
+* Reentrant:   Yes
+* $Id$
+*-------------------------------------------------------------------------
+* Copyright (c) 2003-2004 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would
+*    be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not
+*    be misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* Marcus Geelnard
+* marcus.geelnard at home.se
+*************************************************************************/
+
+#ifndef _lz_h_
+#define _lz_h_
+
+
+
+/*************************************************************************
+* Function prototypes
+*************************************************************************/
+
+int LZ_Compress( unsigned char *in, unsigned char *out,
+                 unsigned int insize );
+int LZ_CompressFast( unsigned char *in, unsigned char *out,
+                     unsigned int insize, unsigned int *work );
+void LZ_Uncompress( unsigned char *in, unsigned char *out,
+                    unsigned int insize );
+
+
+#endif /* _lz_h_ */


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/compressor/lz.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/console2.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/console2.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/console2.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,124 @@
+//////////////////////////////////////////////////////////////////////
+//
+// consol.h --provides basic consol type print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+#ifndef CONSOLE_H2
+#define CONSOLE_H2
+
+#define CONSOLE_USE_COLOR255 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth);
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth);
+
+void consolePrintf(const char* s, ...);
+
+void consolePrintSet(int x, int y);
+
+void consolePrintChar(char c);
+
+void consolePutString(int x, int y, char* s);
+void consolePutInt(int x, int y, int d);
+void consolePutX(int x, int y, int d);
+void consolePutChar(int x, int y, char c);
+void consolePutBin(int x, int y, int b);
+
+void consoleClear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+//////////////////////////////////////////////////////////////////////
+//
+// consol.h --provides basic consol type print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+#ifndef CONSOLE_H2
+#define CONSOLE_H2
+
+#define CONSOLE_USE_COLOR255 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth);
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth);
+
+void consolePrintf(const char* s, ...);
+
+void consolePrintSet(int x, int y);
+
+void consolePrintChar(char c);
+
+void consolePutString(int x, int y, char* s);
+void consolePutInt(int x, int y, int d);
+void consolePutX(int x, int y, int d);
+void consolePutChar(int x, int y, char c);
+void consolePutBin(int x, int y, int b);
+
+void consoleClear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/console2.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/dsmain.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/dsmain.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/dsmain.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,3888 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+
+#include <nds.h>
+
+#include <ARM9/console.h> //basic print funcionality
+
+#include <stdlib.h>
+#include "dsmain.h"
+#include "string.h"
+#include "system.h"
+#include "osystem_ds.h"
+#include "icons_raw.h"
+#include "gba_nds_fat.h"
+#include "disc_io.h"
+#include "config-manager.h"
+#include "engines/scumm/scumm.h"
+#include "keyboard_raw.h"
+#include "keyboard_pal_raw.h"
+#define V16(a, b) ((a << 12) | b)
+#include "touchkeyboard.h"
+#include "registers_alt.h"
+//#include "compact_flash.h"
+#include "dsoptions.h"
+
+namespace DS {
+
+// From console.c in NDSLib
+
+//location of cursor
+extern u8 row;
+extern u8 col;
+
+// Mouse mode
+enum MouseMode {
+	MOUSE_LEFT, MOUSE_RIGHT, MOUSE_HOVER, MOUSE_NUM_MODES
+};
+
+// Defines
+#define FRAME_TIME 17
+#define SCUMM_GAME_HEIGHT 142
+#define SCUMM_GAME_WIDTH 232
+
+int textureID;
+u16* texture;
+
+int frameCount;
+int currentTimeMillis;
+
+// Timer Callback
+int callbackInterval;
+int callbackTimer;
+OSystem::TimerProc callback;
+
+// Scaled
+bool scaledMode;
+int scX;
+int scY;
+
+int subScX;
+int subScY;
+int subScTargetX;
+int subScTargetY;
+int subScreenWidth = SCUMM_GAME_WIDTH;
+int subScreenHeight = SCUMM_GAME_HEIGHT;
+int subScreenScale = 256;
+
+
+
+// Sound
+int bufferSize;
+s16* soundBuffer;
+int bufferFrame;
+int bufferRate;
+int bufferSamples;
+bool soundHiPart;
+
+// Events
+int lastEventFrame;
+bool indyFightState;
+bool indyFightRight;
+
+OSystem::SoundProc soundCallback;
+void* soundParam;
+int lastCallbackFrame;
+bool bufferFirstHalf;
+bool bufferSecondHalf;
+
+// Saved buffers
+u8* savedBuffer = NULL;
+bool highBuffer;
+bool displayModeIs8Bit;
+
+// Game id
+u8 gameID;
+
+bool consoleEnable = true;
+bool gameScreenSwap = false;
+
+MouseMode mouseMode;
+
+// Sprites
+SpriteEntry sprites[128];
+SpriteEntry spritesMain[128];
+int tweak;
+
+// Shake
+int shakePos = 0;
+
+// Keyboard
+bool keyboardEnable = false;
+bool leftHandedMode = false;
+bool keyboardIcon = false;
+
+// Touch
+int touchScX, touchScY, touchX, touchY;
+
+// Dragging
+int dragStartX, dragStartY;
+bool dragging = false;
+int dragScX, dragScY;
+
+// Interface styles
+char gameName[32];
+
+// 8-bit surface size
+int gameWidth = 320;
+int gameHeight = 200;
+
+enum controlType {
+	CONT_SCUMM_ORIGINAL,
+	CONT_SCUMM_SAMNMAX,
+	CONT_SKY,
+	CONT_SIMON,
+};
+
+struct gameListType {
+	char 			gameId[16];
+	controlType 	control;
+};
+
+#define NUM_SUPPORTED_GAMES 15
+
+gameListType gameList[NUM_SUPPORTED_GAMES] = {
+	// Unknown game - use normal SCUMM controls
+	{"unknown", 	CONT_SCUMM_ORIGINAL},
+	
+	// SCUMM games
+	{"maniac",		CONT_SCUMM_ORIGINAL},
+	{"zak",			CONT_SCUMM_ORIGINAL},
+	{"loom",		CONT_SCUMM_ORIGINAL},
+	{"indy3",		CONT_SCUMM_ORIGINAL},
+	{"atlantis",	CONT_SCUMM_ORIGINAL},
+	{"monkey",		CONT_SCUMM_ORIGINAL},
+	{"monkey2",		CONT_SCUMM_ORIGINAL},
+	{"tentacle",	CONT_SCUMM_ORIGINAL},
+	{"samnmax",		CONT_SCUMM_SAMNMAX},
+	
+	// Non-SCUMM games
+	{"sky",			CONT_SKY},
+	{"simon1",		CONT_SIMON},
+	{"simon2",		CONT_SIMON},
+	{"gob1",		CONT_SCUMM_ORIGINAL},
+	{"queen",		CONT_SCUMM_ORIGINAL}
+};
+
+gameListType* currentGame = NULL;
+
+// Stylus
+#define ABS(x) ((x)>0?(x):-(x))
+
+bool penDown;
+bool penHeld;
+bool penReleased;
+bool penDownLastFrame;
+f32 penX, penY;
+int keysDownSaved;
+int keysReleasedSaved;
+
+bool penDownSaved;
+bool penReleasedSaved;
+int penDownFrames;
+int touchXOffset = 0;
+int touchYOffset = 0;
+
+u16 savedPalEntry255 = RGB15(31, 31, 31);
+
+
+extern "C" int scummvm_main(int argc, char *argv[]);
+void updateStatus();
+
+TransferSound soundControl;
+
+//plays an 8 bit mono sample at 11025Hz
+void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate)
+{
+	
+	if (!IPC->soundData) {
+		soundControl.count = 0;
+	}
+	
+	soundControl.data[soundControl.count].data = data;
+	soundControl.data[soundControl.count].len = length | (loop? 0x80000000: 0x00000000);
+	soundControl.data[soundControl.count].rate = rate;		// 367 samples per frame
+	soundControl.data[soundControl.count].pan = 64;
+	soundControl.data[soundControl.count].vol = 127;
+	soundControl.data[soundControl.count].format = adpcm? 2: 0;
+
+	soundControl.count++;
+
+	DC_FlushAll();
+	IPC->soundData = &soundControl;
+}
+
+void stopSound(int channel) {
+	playSound(NULL, 0, false, false, -channel);
+}
+
+void updateOAM() {
+	DC_FlushAll();
+    dmaCopy(sprites, OAM_SUB, 128 * sizeof(SpriteEntry));
+    dmaCopy(spritesMain, OAM, 128 * sizeof(SpriteEntry));
+}
+
+void setGameSize(int width, int height) {
+	gameWidth = width;
+	gameHeight = height;
+}
+
+int getGameWidth() {
+	return gameWidth;
+}
+
+int getGameHeight() {
+	return gameHeight;
+}
+
+void initSprites() {
+	for(int i = 0; i < 128; i++) {
+	   sprites[i].attribute[0] = ATTR0_DISABLED;
+	   sprites[i].attribute[1] = 0;
+	   sprites[i].attribute[2] = 0;
+	   sprites[i].attribute[3] = 0;
+    }
+	
+	for(int i = 0; i < 128; i++) {
+	   spritesMain[i].attribute[0] = ATTR0_DISABLED;
+	   spritesMain[i].attribute[1] = 0;
+	   spritesMain[i].attribute[2] = 0;
+	   spritesMain[i].attribute[3] = 0;
+    }
+	
+	updateOAM();
+}
+
+
+void saveGameBackBuffer() {
+#ifdef DISABLE_SCUMM
+	if (savedBuffer == NULL) savedBuffer = new u8[gameWidth * gameHeight];
+	for (int r = 0; r < 200; r++) {
+		memcpy(savedBuffer + (r * gameWidth), ((u8 *) (get8BitBackBuffer())) + (r * 512), gameWidth);
+	}
+#endif
+}
+
+void restoreGameBackBuffer() {
+#ifdef DISABLE_SCUMM
+	if (savedBuffer) {
+		for (int r = 0; r < 200; r++) {
+			memcpy(((u8 *) (BG_GFX_SUB)) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+			memcpy(((u8 *) (get8BitBackBuffer())) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+		}
+		delete savedBuffer;
+		savedBuffer = NULL;
+	}
+#endif
+
+#ifndef DISABLE_SCUMM	
+	memset(get8BitBackBuffer(), 0, 512 * 256);
+	memset(BG_GFX_SUB, 0, 512 * 256);
+	if (Scumm::g_scumm) {
+		Scumm::g_scumm->markRectAsDirty(Scumm::kMainVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+		Scumm::g_scumm->markRectAsDirty(Scumm::kTextVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+		Scumm::g_scumm->markRectAsDirty(Scumm::kVerbVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+	}
+#endif
+
+}
+
+
+void initGame() {
+	// This is a good time to check for left handed mode since the mode change is done as the game starts.
+	// There's probably a better way, but hey.
+//	consolePrintf("initing game\n");
+
+	setOptions();
+
+	//strcpy(gameName, ConfMan.getActiveDomain().c_str());
+	strcpy(gameName, ConfMan.get("gameid").c_str());
+//	consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
+
+	currentGame = &gameList[0];		// Default game
+	
+	for (int r = 0; r < NUM_SUPPORTED_GAMES; r++) {
+		if (!stricmp(gameName, gameList[r].gameId)) {
+			currentGame = &gameList[r];
+//			consolePrintf("Game list num: %d\n", currentGame);
+		}
+	}
+	
+
+}
+
+void setLeftHanded(bool enable) {
+	leftHandedMode = enable;
+}
+
+void setTouchXOffset(int x) {
+	touchXOffset = x;
+}
+
+void setTouchYOffset(int y) {
+	touchYOffset = y;
+}
+
+void setUnscaledMode(bool enable) {
+	scaledMode = !enable;
+}
+
+void displayMode8Bit() {
+
+	u16 buffer[32 * 32];
+	
+	setKeyboardEnable(false);
+
+	if (!displayModeIs8Bit) {
+		for (int r = 0; r < 32 * 32; r++) {
+			buffer[r] = ((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r];
+		}
+	}
+	
+	
+
+	videoSetMode(MODE_5_2D | (consoleEnable? DISPLAY_BG0_ACTIVE: 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); 
+	videoSetModeSub(MODE_3_2D /*| DISPLAY_BG0_ACTIVE*/ | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+
+	vramSetBankA(VRAM_A_MAIN_BG_0x6000000);
+	vramSetBankB(VRAM_B_MAIN_BG_0x6020000);
+
+	vramSetBankC(VRAM_C_SUB_BG_0x6200000);
+	vramSetBankD(VRAM_D_MAIN_BG_0x6040000);
+	
+	vramSetBankH(VRAM_H_LCD);
+
+	BG3_CR = BG_BMP8_512x256 | BG_BMP_BASE(8);
+	
+	
+	
+	BG3_XDX = (int) (((float) (gameWidth) / 256.0f) * 256);
+    BG3_XDY = 0;
+    BG3_YDX = 0;
+    BG3_YDY = (int) ((200.0f / 192.0f) * 256);
+
+	SUB_BG3_CR = BG_BMP8_512x256;
+	
+	
+	
+	SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
+    SUB_BG3_XDY = 0;
+    SUB_BG3_YDX = 0;
+    SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);
+
+
+	// Do text stuff
+	BG0_CR = BG_MAP_BASE(0) | BG_TILE_BASE(1);
+	BG0_Y0 = 0;
+	
+	// Restore palette entry used by text in the front-end	
+	PALETTE_SUB[255] = savedPalEntry255;
+	
+	consoleInitDefault((u16*)SCREEN_BASE_BLOCK(0), (u16*)CHAR_BASE_BLOCK(1), 16);
+	consolePrintSet(0, 23);
+	
+	if (!displayModeIs8Bit) {
+		for (int r = 0; r < 32 * 32; r++) {
+			((u16 *) SCREEN_BASE_BLOCK(0))[r] = buffer[r];
+		}
+//		dmaCopyHalfWords(3, (u16 *) SCREEN_BASE_BLOCK(0), buffer, 32 * 32 * 2);
+	}
+	
+	
+	if (!displayModeIs8Bit) restoreGameBackBuffer();
+	displayModeIs8Bit = true;
+	
+	POWER_CR &= ~POWER_SWAP_LCDS;
+	
+	keyboardEnable = false;
+	initGame();
+	
+}
+
+void setGameID(int id) {
+	gameID = id;
+}
+
+void dummyHandler() {
+	REG_IF = IRQ_VBLANK;
+}
+
+void checkSleepMode() {
+	if (IPC->performArm9SleepMode) {
+	
+		consolePrintf("ARM9 Entering sleep mode\n");
+		
+		int intSave = REG_IE;
+		irqSet(IRQ_VBLANK, dummyHandler);
+//		int irqHandlerSave = (int) IRQ_HANDLER;
+		REG_IE = IRQ_VBLANK;
+		//IRQ_HANDLER = dummyHandler;
+		
+		int powerSave = POWER_CR;
+		POWER_CR &= ~POWER_ALL;
+		
+		while (IPC->performArm9SleepMode) {
+			swiWaitForVBlank();
+		}
+		
+		POWER_CR = powerSave;
+//		IRQ_HANDLER = (void (*)()) irqHandlerSave;
+		irqSet(IRQ_VBLANK, VBlankHandler);
+		REG_IE = intSave;
+
+		consolePrintf("ARM9 Waking from sleep mode\n");
+	}
+}
+
+void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor) {
+	if (currentGame->control != CONT_SCUMM_SAMNMAX)
+		return;
+
+	uint16 border = RGB15(24,24,24) | 0x8000;
+	
+	
+	int off = 48*64;
+	memset(SPRITE_GFX_SUB+off, 0, 64*64*2);
+	
+	int pos = 190 - (w+2);
+	
+
+	
+	// make border
+	for (uint i=0; i<w+2; i++) {
+		SPRITE_GFX_SUB[off+i] = border;
+		SPRITE_GFX_SUB[off+(31)*64+i] = border;
+	}
+	for (uint i=1; i<31; i++) {
+		SPRITE_GFX_SUB[off+(i*64)] = border;
+		SPRITE_GFX_SUB[off+(i*64)+(w+1)] = border;
+	}
+	
+	int offset = (32 - h) >> 1;
+
+	for (uint y=0; y<h; y++) {
+		for (uint x=0; x<w; x++) {
+			int color = icon[y*w+x];
+			if (color == keycolor) {
+				SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = 0x8000; // black background
+			} else {
+				SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = BG_PALETTE[color] | 0x8000;
+			}
+		}
+	}
+
+	sprites[1].attribute[0] = ATTR0_BMP | 150;
+	sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
+	sprites[1].attribute[2] = ATTR2_ALPHA(1) | 48;
+}
+
+
+
+
+void displayMode16Bit() {
+
+	u16 buffer[32 * 32 * 2];
+
+
+	if (displayModeIs8Bit) {
+		saveGameBackBuffer();
+		for (int r = 0; r < 32 * 32; r++) {
+			buffer[r] = ((u16 *) SCREEN_BASE_BLOCK(0))[r];
+		}
+	}
+
+
+	videoSetMode(MODE_5_2D | /*DISPLAY_BG0_ACTIVE |*/ DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); 
+	videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE |/* DISPLAY_BG1_ACTIVE |*/ DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+
+	vramSetBankA(VRAM_A_MAIN_BG);
+	vramSetBankB(VRAM_B_MAIN_BG);
+	vramSetBankC(VRAM_C_MAIN_BG);
+	vramSetBankD(VRAM_D_MAIN_BG);
+	vramSetBankH(VRAM_H_SUB_BG);
+
+	BG3_CR = BG_BMP16_512x256;
+	highBuffer = false;
+	
+	BG3_XDX = (int) (1.25f * 256);
+    BG3_XDY = 0;
+    BG3_YDX = 0;
+    BG3_YDY = (int) ((200.0f / 192.0f) * 256);
+
+	memset(BG_GFX, 0, 512 * 256 * 2);
+	
+	savedPalEntry255 = PALETTE_SUB[255];
+	PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
+
+	// Do text stuff
+	SUB_BG0_CR = BG_MAP_BASE(4) | BG_TILE_BASE(0);
+	SUB_BG0_Y0 = 0;
+
+	consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(4), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
+
+	if (displayModeIs8Bit) {
+		//dmaCopyHalfWords(3, (u16 *) SCREEN_BASE_BLOCK_SUB(0), buffer, 32 * 32 * 2);
+		for (int r = 0; r < 32 * 32; r++) {
+			((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r] = buffer[r];
+		}
+	}
+
+	consolePrintSet(0, 23);
+	consolePrintf("\n");
+	
+	// Show keyboard
+	SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
+	//drawKeyboard(1, 12);
+	
+	POWER_CR &= ~POWER_SWAP_LCDS;
+
+
+
+	displayModeIs8Bit = false;
+}
+
+
+void displayMode16BitFlipBuffer() {
+	if (!displayModeIs8Bit) {
+		u16* back = get16BitBackBuffer();
+	
+//		highBuffer = !highBuffer;
+//		BG3_CR = BG_BMP16_512x256 |	BG_BMP_RAM(highBuffer? 1: 0);
+		
+		for (int r = 0; r < 512 * 256; r++) {
+			*(BG_GFX + r) = *(back + r);
+		}
+	}
+}
+
+void setShakePos(int shakePos) {
+	shakePos = shakePos;
+}
+
+
+u16* get16BitBackBuffer() {
+	return BG_GFX + 0x20000;
+}
+
+u16* get8BitBackBuffer() {
+	return BG_GFX + 0x10000;		// 16bit qty!
+}
+
+void setSoundProc(OSystem::SoundProc proc, void* param) {
+//	consolePrintf("Set sound callback");
+	soundCallback = proc;
+	soundParam = param;
+}
+
+// The sound system in ScummVM seems to always return stereo interleaved samples.
+// Here, I'm treating an 11Khz stereo stream as a 22Khz mono stream, which works sorta ok, but is
+// a horrible bodge.  Any advice on how to change the engine to output mono would be greatly
+// appreciated.
+void doSoundCallback() {
+	if ((soundCallback)) {
+		lastCallbackFrame = frameCount;
+		
+		for (int r = IPC->playingSection; r < IPC->playingSection + 4; r++) {
+			int chunk = r & 3;
+			
+			if (IPC->fillNeeded[chunk]) {
+				IPC->fillNeeded[chunk] = false;
+				DC_FlushAll();
+				soundCallback(soundParam, (byte *) (soundBuffer + ((bufferSamples >> 2) * chunk)), bufferSamples >> 1);
+				IPC->fillNeeded[chunk] = false;
+				DC_FlushAll();
+			}
+		
+		}
+		
+	}
+}
+
+void doTimerCallback() {
+	if (callback) {
+		if (callbackTimer <= 0) {
+			callbackTimer += callbackInterval;
+			callback(callbackInterval);
+		}	
+	}
+}
+
+void soundUpdate() {
+	if ((bufferFrame == 0)) {
+//		playSound(soundBuffer, (bufferSamples * 2), true);
+	}
+//	consolePrintf("%x\n", IPC->test);
+	
+	
+	if (bufferFrame == 0) {
+//		bufferFirstHalf = true;
+	}	
+	if (bufferFrame == bufferSize >> 1) {
+	//bufferSecondHalf = true;
+	}	
+	
+	bufferFrame++;
+	if (bufferFrame == bufferSize) {
+		bufferFrame = 0;
+	}
+}
+
+void memoryReport() {
+	int r = 0;
+	int* p;
+	do {
+		p = (int *) malloc(r * 8192);
+		free(p);
+		r++;		
+	} while ((p) && (r < 512));
+	
+	int t = -1;
+	void* block[1024];
+	do {
+		t++;
+		block[t] = (int *) malloc(4096);
+	} while ((t < 1024) && (block[t]));		
+	
+	for (int q = 0; q < t; q++) {
+		free(block[q]);
+	}
+	
+	consolePrintf("Free: %dK, Largest: %dK\n", t * 4, r * 8);
+}
+
+
+void addIndyFightingKeys() {
+	OSystem_DS* system = OSystem_DS::instance();
+	OSystem::Event event;
+
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.flags = 0;
+
+	if ((getKeysDown() & KEY_L)) {
+		indyFightRight = false;
+	}
+
+	if ((getKeysDown() & KEY_R)) {
+		indyFightRight = true;
+	}
+
+	if ((getKeysDown() & KEY_UP)) {
+		event.kbd.keycode = '8';
+		event.kbd.ascii = '8';
+		system->addEvent(event);
+	}
+	if ((getKeysDown() & KEY_LEFT)) {
+		event.kbd.keycode = '4';
+		event.kbd.ascii = '4';
+		system->addEvent(event);
+	}
+	if ((getKeysDown() & KEY_RIGHT)) {
+		event.kbd.keycode = '6';
+		event.kbd.ascii = '6';
+		system->addEvent(event);
+	}	
+	if ((getKeysDown() & KEY_DOWN)) {
+		event.kbd.keycode = '2';
+		event.kbd.ascii = '2';
+		system->addEvent(event);
+	}
+	
+	if (indyFightRight) {
+	
+		if ((getKeysDown() & KEY_X)) {
+			event.kbd.keycode = '9';
+			event.kbd.ascii = '9';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_A)) {
+			event.kbd.keycode = '6';
+			event.kbd.ascii = '6';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_B)) {
+			event.kbd.keycode = '3';
+			event.kbd.ascii = '3';
+			system->addEvent(event);
+		}	
+
+	} else {
+
+		if ((getKeysDown() & KEY_X)) {
+			event.kbd.keycode = '7';
+			event.kbd.ascii = '7';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_A)) {
+			event.kbd.keycode = '4';
+			event.kbd.ascii = '4';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_B)) {
+			event.kbd.keycode = '1';
+			event.kbd.ascii = '1';
+			system->addEvent(event);
+		}	
+	
+	}
+	
+	
+	if ((getKeysDown() & KEY_Y)) {
+		event.kbd.keycode = '5';
+		event.kbd.ascii = '5';
+		system->addEvent(event);
+	}
+} 			
+
+
+void setKeyboardEnable(bool en) {
+	if (en == keyboardEnable) return;
+	keyboardEnable = en;
+	u16* backupBank = (u16 *) 0x6040000;
+
+	if (keyboardEnable) {
+
+
+		DS::drawKeyboard(1, 12, backupBank);
+		
+		
+		SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
+
+		if (displayModeIs8Bit) {
+			SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE;	// Turn on keyboard layer
+			SUB_DISPLAY_CR &= ~DISPLAY_BG3_ACTIVE;	// Turn off game layer
+		} else {
+			SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE;	// Turn on keyboard layer
+			SUB_DISPLAY_CR &= ~DISPLAY_BG0_ACTIVE;	// Turn off console layer
+		}
+		lcdSwap();
+	} else {
+
+
+		// Restore the palette that the keyboard has used
+		for (int r = 0; r < 256; r++) {
+			BG_PALETTE_SUB[r] = BG_PALETTE[r];
+		}
+		
+		
+		//restoreVRAM(1, 12, backupBank);
+		
+		if (displayModeIs8Bit) {
+			// Copy the sub screen VRAM from the top screen - they should always be
+			// the same.
+			for (int r = 0; r < (512 * 256) >> 1; r++) {
+				BG_GFX_SUB[r] = get8BitBackBuffer()[r];
+			}
+			
+			SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE;	// Turn off keyboard layer
+			SUB_DISPLAY_CR |= DISPLAY_BG3_ACTIVE;	// Turn on game layer
+		} else {
+			SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE;	// Turn off keyboard layer
+			SUB_DISPLAY_CR |= DISPLAY_BG0_ACTIVE;	// Turn on console layer
+		}
+		
+		lcdSwap();
+	}
+}
+
+bool getKeyboardEnable() {
+	return keyboardEnable;
+}
+
+bool getIsDisplayMode8Bit() {
+	return displayModeIs8Bit;
+}
+
+void addEventsToQueue() {
+	OSystem_DS* system = OSystem_DS::instance();
+	OSystem::Event event;
+
+	
+
+	
+	if (system->isEventQueueEmpty()) {
+
+/*
+		if (getKeysDown() & KEY_L) {
+			tweak--;
+			consolePrintf("Tweak: %d\n", tweak);
+			IPC->tweakChanged = true;
+		}
+		
+
+		if (getKeysDown() & KEY_R) {
+			tweak++;
+			consolePrintf("Tweak: %d\n", tweak);
+			IPC->tweakChanged = true;
+		}
+	*/
+		if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
+			memoryReport();
+		}
+
+		if (displayModeIs8Bit) {
+
+			if (!indyFightState) {
+
+				
+				if ((getKeysDown() & KEY_B) && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+		//			consolePrintf("Pressing Esc");
+		
+					event.type = OSystem::EVENT_KEYDOWN;
+					event.kbd.keycode = 27;		
+					event.kbd.ascii = 27;		
+					event.kbd.flags = 0;
+					system->addEvent(event);
+				}
+		
+			}
+			
+		
+			
+			if ((!getIndyFightState()) && (getKeysDown() & KEY_Y)) {
+				consoleEnable = !consoleEnable;
+				if (displayModeIs8Bit) {
+					displayMode8Bit();
+				} else {
+					displayMode16Bit();
+				}
+			}
+	
+	
+			if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState())) {
+
+				if ((getKeysDown() & KEY_A) && (!indyFightState)) {
+					gameScreenSwap = !gameScreenSwap;
+				}
+	
+				if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) {
+					if (getKeysDown() & KEY_LEFT) {
+						mouseMode = MOUSE_LEFT;
+					}
+					if (getKeysDown() & KEY_RIGHT) {
+						if (currentGame->control != CONT_SCUMM_SAMNMAX) {
+							mouseMode = MOUSE_RIGHT;
+						} else {
+							// If we're playing sam and max, click and release the right mouse
+							// button to change verb
+							OSystem::Event event;
+		
+							event.type = OSystem::EVENT_RBUTTONDOWN;
+							event.mouse = Common::Point(getPenX(), getPenY());
+							system->addEvent(event);
+		
+							event.type = OSystem::EVENT_RBUTTONUP;
+							system->addEvent(event);
+						}
+					}
+					if (getKeysDown() & KEY_UP) {
+						mouseMode = MOUSE_HOVER;
+					}
+				}
+	
+					
+				
+			}
+
+			if ((getKeysDown() & KEY_SELECT)) {
+				//scaledMode = !scaledMode;
+				//scY = 4;
+				showOptionsDialog();
+			}
+
+			
+		}
+	
+		if (!getIndyFightState() && !((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (getKeysDown() & KEY_X)) {
+			setKeyboardEnable(!keyboardEnable);
+		}
+		
+		updateStatus();			
+		
+		OSystem::Event event;
+
+		if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+			event.type = OSystem::EVENT_MOUSEMOVE;
+			event.mouse = Common::Point(getPenX(), getPenY());
+			system->addEvent(event);
+			//consolePrintf("x=%d   y=%d  \n", getPenX(), getPenY());
+		}
+	
+		if (!keyboardEnable) {
+			if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
+					if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {	
+						event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? OSystem::EVENT_LBUTTONDOWN: OSystem::EVENT_RBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+					
+					if (getPenReleased()) {
+						event.type = mouseMode == MOUSE_LEFT? OSystem::EVENT_LBUTTONUP: OSystem::EVENT_RBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+			} else {
+				// In hover mode, D-pad left and right click the mouse when the pen is on the screen
+	
+				if (getPenHeld()) {
+					if (getKeysDown() & KEY_LEFT) {
+						event.type = OSystem::EVENT_LBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+				/*	if (getKeysReleased() & KEY_LEFT) {
+						event.type = OSystem::EVENT_LBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}*/
+	
+					if (getKeysDown() & KEY_RIGHT) {
+						event.type = OSystem::EVENT_RBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+					/*if (getKeysReleased() & KEY_RIGHT) {
+						event.type = OSystem::EVENT_RBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}*/
+				}
+			}
+			
+			if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))  && (displayModeIs8Bit)) {
+				// Controls specific to the control method
+			
+			
+				if (currentGame->control == CONT_SKY) {
+					// Extra controls for Benieth a Steel Sky
+					if ((getKeysDown() & KEY_DOWN)) {
+						penY = 0;
+						penX = 0;		// Show inventory by moving mouse onto top line
+					}
+				}
+
+				if (currentGame->control == CONT_SIMON) {
+					// Extra controls for Simon the Sorcerer
+					if ((getKeysDown() & KEY_DOWN)) {
+						OSystem::Event event;
+					
+						event.type = OSystem::EVENT_KEYDOWN;
+						event.kbd.keycode = '#';		// F10 or # - show hotspots
+						event.kbd.ascii = '#';
+						event.kbd.flags = 0;
+						system->addEvent(event);
+//						consolePrintf("F10\n");
+					}
+				}
+	
+				if (currentGame->control == CONT_SCUMM_ORIGINAL) {
+					// Extra controls for Scumm v1-5 games
+					if ((getKeysDown() & KEY_DOWN)) {
+						OSystem::Event event;
+					
+						event.type = OSystem::EVENT_KEYDOWN;
+						event.kbd.keycode = '.';		// Full stop - skips current dialogue line
+						event.kbd.ascii = '.';
+						event.kbd.flags = 0;
+						system->addEvent(event);
+					}
+					
+					if (indyFightState) {
+						addIndyFightingKeys();
+					}
+					
+				}
+				
+			}
+		}
+		
+		if (!displayModeIs8Bit) {
+			// Front end controls
+			
+			if (leftHandedSwap(getKeysDown()) & KEY_UP) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_UP;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+
+			if (leftHandedSwap(getKeysDown()) & KEY_DOWN) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_DOWN;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+
+			if (leftHandedSwap(getKeysDown()) & KEY_A) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_RETURN;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+		
+		}
+
+		
+		if ((getKeysDown() & KEY_START)) {
+			event.type = OSystem::EVENT_KEYDOWN;
+			event.kbd.keycode = 319;		// F5
+			event.kbd.ascii = 319;
+			event.kbd.flags = 0;
+			system->addEvent(event);
+/*
+			event.type = OSystem::EVENT_KEYUP;
+			event.kbd.keycode = 319;		// F5
+			event.kbd.ascii = 319;
+			system->addEvent(event);*/
+			
+//			consolePrintf("Pressing F5");
+		}
+
+		
+		if (keyboardEnable) {
+			DS::addKeyboardEvents();
+		}
+		
+		consumeKeys();
+		
+		consumePenEvents();
+
+	}
+}
+
+void updateStatus() {
+	int offs;
+
+	if (displayModeIs8Bit) {
+		switch (mouseMode) {
+			case MOUSE_LEFT: {
+				offs = 16;
+				break;
+			}
+			case MOUSE_RIGHT: {
+				offs = 32;
+				break;
+			}
+			case MOUSE_HOVER: {
+				offs = 0;
+				break;
+			}
+			default: {
+				// Nothing!
+				offs = 0;
+				break;
+			}
+		}
+	
+		
+		sprites[0].attribute[0] = ATTR0_BMP | 150; 
+		sprites[0].attribute[1] = ATTR1_SIZE_32 | 208;
+		sprites[0].attribute[2] = ATTR2_ALPHA(1)| offs;
+	
+		if (indyFightState) {
+			sprites[2].attribute[0] = ATTR0_BMP | 150; 
+			sprites[2].attribute[1] = ATTR1_SIZE_32 | (190 - 32) | (indyFightRight? 0: ATTR1_FLIP_X);
+			sprites[2].attribute[2] = ATTR2_ALPHA(1)| 48;
+		} else {
+			sprites[2].attribute[0] = ATTR0_DISABLED; 
+			sprites[2].attribute[1] = 0;
+			sprites[2].attribute[2] = 0;
+		}
+	} else {
+		sprites[0].attribute[0] = ATTR0_DISABLED; 
+		sprites[1].attribute[0] = ATTR0_DISABLED; 
+		sprites[2].attribute[0] = ATTR0_DISABLED; 
+		sprites[3].attribute[0] = ATTR0_DISABLED; 
+	}
+
+	if ((keyboardIcon) && (!keyboardEnable) && (!displayModeIs8Bit)) {
+		spritesMain[0].attribute[0] = ATTR0_BMP | 160;
+		spritesMain[0].attribute[1] = ATTR1_SIZE_32 | 0;
+		spritesMain[0].attribute[2] = ATTR2_ALPHA(1) | 64;
+	} else {
+		spritesMain[0].attribute[0] = ATTR0_DISABLED;
+		spritesMain[0].attribute[1] = 0;
+		spritesMain[0].attribute[2] = 0;
+		spritesMain[0].attribute[3] = 0;
+	}
+
+}
+
+void soundBufferEmptyHandler() {
+	REG_IF = IRQ_TIMER2;
+
+	if (soundHiPart) {
+//		bufferSecondHalf = true;
+	} else {
+//		bufferFirstHalf = true;
+	}
+	
+	soundHiPart = !soundHiPart;
+}
+
+void setMainScreenScroll(int x, int y) {
+	if (gameScreenSwap) {
+		SUB_BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		SUB_BG3_CY = y;
+	} else {
+		BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		BG3_CY = y;
+		
+		touchX = x >> 8;
+		touchY = y >> 8;
+	}
+}
+
+void setMainScreenScale(int x, int y) {
+	if (gameScreenSwap) {
+		SUB_BG3_XDX = x;
+		SUB_BG3_XDY = 0;
+		SUB_BG3_YDX = 0;
+		SUB_BG3_YDY = y;
+	} else {
+		BG3_XDX = x;
+		BG3_XDY = 0;
+		BG3_YDX = 0;
+		BG3_YDY = y;
+		
+		touchScX = x;
+		touchScY = y;
+	}
+}
+
+void setZoomedScreenScroll(int x, int y) {
+	if (gameScreenSwap) {
+		BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		BG3_CY = y;
+		
+		touchX = x >> 8;
+		touchY = y >> 8;
+	} else {
+		SUB_BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		SUB_BG3_CY = y;
+	}
+}
+
+void setZoomedScreenScale(int x, int y) {
+	if (gameScreenSwap) {
+		BG3_XDX = x;
+		BG3_XDY = 0;
+		BG3_YDX = 0;
+		BG3_YDY = y;
+
+		touchScX = x;
+		touchScY = y;
+	} else {
+		SUB_BG3_XDX = x;
+		SUB_BG3_XDY = 0;
+		SUB_BG3_YDX = 0;
+		SUB_BG3_YDY = y;
+	}
+}
+
+void VBlankHandler(void) {
+//	BG_PALETTE[0] = RGB15(31, 31, 31);
+//	if (*((int *) (0x023FFF00)) != 0xBEEFCAFE) {
+	//	consolePrintf("Guard band overwritten!");
+//  }
+
+//	consolePri ntf("X:%d Y:%d\n", getPenX(), getPenY());
+
+
+	IPC->tweak = tweak;
+	soundUpdate();
+
+
+	
+
+	if ((!gameScreenSwap) && (!(getKeysHeld() & KEY_L) && !(getKeysHeld() & KEY_R))) {
+		if (currentGame) {
+			if (currentGame->control != CONT_SCUMM_SAMNMAX) {
+				if (getPenHeld() && (getPenY() < SCUMM_GAME_HEIGHT)) {
+					setTopScreenTarget(getPenX(), getPenY());
+				}
+			} else {
+				if (getPenHeld()) {
+					setTopScreenTarget(getPenX(), getPenY());
+				}
+			}
+		}
+	}
+	
+
+	penUpdate();
+	keysUpdate();
+
+
+	frameCount++;
+	
+
+
+	if (callback) {
+		callbackTimer -= FRAME_TIME;
+	}
+	
+	if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+	
+		if ((!dragging) && (getPenHeld()) && (penDownFrames > 5)) {
+			dragging = true;
+			dragStartX = penX;
+			dragStartY = penY;
+			
+			if (gameScreenSwap) {
+				dragScX = subScTargetX;
+				dragScY = subScTargetY;
+			} else {
+				dragScX = scX;
+				dragScY = scY;				
+			}	
+			
+			
+		}
+		
+		if ((dragging) && (!getPenHeld())) {
+			dragging = false;
+		}
+		
+		if (dragging) {
+		
+			if (gameScreenSwap) {
+				subScTargetX = dragScX + ((dragStartX - penX) << 8);
+				subScTargetY = dragScY + ((dragStartY - penY) << 8);
+			} else {
+				scX = dragScX + ((dragStartX - penX));
+				scY = dragScY + ((dragStartY - penY));
+			}
+			
+//			consolePrintf("X:%d Y:%d\n", dragStartX - penX, dragStartY - penY);
+		}
+	}	
+	
+	
+/*	if ((frameCount & 1) == 0) {
+		SUB_BG3_CX = subScX;
+	} else {
+		SUB_BG3_CX = subScX + 64;
+	}
+	
+	SUB_BG3_CY = subScY + (shakePos << 8);*/
+
+	/*SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
+    SUB_BG3_XDY = 0;
+    SUB_BG3_YDX = 0;
+    SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/
+	
+	
+	if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+		if ((getKeysHeld() & KEY_A) && (subScreenScale < 256)) {
+			subScreenScale += 3;
+		}
+		
+		if ((getKeysHeld() & KEY_B) && (subScreenScale > 128)) {
+			subScreenScale -=3;
+		}
+		
+		int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8);
+		int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8);
+		
+		subScreenWidth = SCUMM_GAME_WIDTH * subScreenScale >> 8;
+		subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8;
+		
+		subScTargetX = xCenter - ((subScreenWidth >> 1) << 8);
+		subScTargetY = yCenter - ((subScreenHeight >> 1) << 8);
+		
+
+		
+
+		if (subScTargetX < 0) subScTargetX = 0;
+		if (subScTargetX > (gameWidth - subScreenWidth) << 8) subScTargetX = (gameWidth - subScreenWidth) << 8;
+	
+		if (subScTargetY < 0) subScTargetY = 0;
+		if (subScTargetY > (gameHeight - subScreenHeight) << 8) subScTargetY = (gameHeight - subScreenHeight) << 8;
+	}
+
+	subScX += (subScTargetX - subScX) >> 2;
+	subScY += (subScTargetY - subScY) >> 2;
+	
+	if (displayModeIs8Bit) {
+	
+		if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+			
+			int offsX = 0, offsY = 0;
+
+
+			if (getKeysHeld() & KEY_LEFT) {
+				offsX -= 1;
+			}
+			
+			if (getKeysHeld() & KEY_RIGHT) {
+				offsX += 1;
+			}
+	
+			if (getKeysHeld() & KEY_UP) {
+				offsY -= 1;
+			}
+	
+			if (getKeysHeld() & KEY_DOWN) {
+				offsY += 1;
+			}
+			
+			if (((gameScreenSwap) && (getKeysHeld() & KEY_L)) || ((!gameScreenSwap) && (getKeysHeld() & KEY_R))) {
+				subScTargetX += offsX << 8;
+				subScTargetY += offsY << 8;
+			} else {
+				scX += offsX;
+				scY += offsY;
+			}
+		}
+
+		if (!scaledMode) {
+			
+			if (scX + 256 > gameWidth - 1) {
+				scX = gameWidth - 1 - 256;
+			}
+	
+			if (scX < 0) {
+				scX = 0;
+			}
+	
+			if (scY + 192 > gameHeight - 1) {
+				scY = gameHeight - 1 - 192;
+			}
+	
+			if (scY < 0) {
+				scY = 0;
+			}
+			
+			setZoomedScreenScroll(subScX, subScY);
+			setZoomedScreenScale(subScreenWidth, (subScreenHeight * 256) / 192);
+	
+		
+			setMainScreenScroll(scX << 8, (scY << 8) + (shakePos << 8));
+			setMainScreenScale(256, 256);		// 1:1 scale
+	
+		} else {
+		
+			if (scY > gameHeight - 192 - 1) {
+				scY = gameHeight - 192 - 1;
+			}
+
+			if (scY < 0) {
+				scY = 0;
+			}
+		
+			setZoomedScreenScroll(subScX, subScY);
+			setZoomedScreenScale(subScreenWidth, (subScreenHeight * 256) / 192);
+	
+			setMainScreenScroll(64, (scY << 8) + (shakePos << 8));
+			setMainScreenScale(320, 256);		// 1:1 scale
+			
+		}
+	} else {
+		setZoomedScreenScroll(0, 0);
+		setZoomedScreenScale(320, 256);
+
+		setMainScreenScroll(0, 0);
+		setMainScreenScale(320, 256);		// 1:1 scale
+	}
+	
+	// Enable on screen keyboard when pen taps icon
+	if ((keyboardIcon) && (penX < 32) && (penY > 160) && (penHeld)) {
+		setKeyboardEnable(true);
+	}
+	
+	if (keyboardEnable) {
+		if (DS::getKeyboardClosed()) {
+			setKeyboardEnable(false);
+		}
+	}
+
+	updateOAM();
+
+	//PALETTE[0] = RGB15(0, 0, 0);
+	REG_IF = IRQ_VBLANK;
+}
+
+int getMillis() {
+	return currentTimeMillis;
+//	return frameCount * FRAME_TIME;
+}
+
+void setTimerCallback(OSystem::TimerProc proc, int interval) {
+//	consolePrintf("Set timer proc %x, int %d\n", proc, interval);
+	callback = proc;
+	callbackInterval = interval;
+	callbackTimer = interval;
+}
+
+void timerTickHandler() {
+	REG_IF = IRQ_TIMER0;
+	if ((callback) && (callbackTimer > 0)) {
+		callbackTimer--;
+	}
+	currentTimeMillis++;
+}
+
+void setTalkPos(int x, int y) {
+//	if (gameID != Scumm::GID_SAMNMAX) {
+//		setTopScreenTarget(x, 0);
+//	} else {
+		setTopScreenTarget(x, y);
+//	}
+}
+
+void setTopScreenTarget(int x, int y) {
+	subScTargetX = (x - (subScreenWidth >> 1));
+	subScTargetY = (y - (subScreenHeight >> 1));
+
+	if (subScTargetX < 0) subScTargetX = 0;
+	if (subScTargetX > gameWidth - subScreenWidth) subScTargetX = gameWidth - subScreenWidth;
+
+	if (subScTargetY < 0) subScTargetY = 0;
+	if (subScTargetY > gameHeight - subScreenHeight) subScTargetY = gameHeight - subScreenHeight;
+	
+	subScTargetX <<=8;
+	subScTargetY <<=8;
+}
+
+void initHardware() {
+	// Guard band
+//((int *) (0x023FFF00)) = 0xBEEFCAFE;
+
+
+	penInit();
+
+	powerON(POWER_ALL);
+/*	vramSetBankA(VRAM_A_MAIN_BG); 
+	vramSetBankB(VRAM_B_MAIN_BG); 
+	vramSetBankC(VRAM_C_SUB_BG); */
+	vramSetBankI(VRAM_I_SUB_SPRITE); 
+	vramSetBankG(VRAM_G_MAIN_SPRITE); 
+	
+	currentTimeMillis = 0;
+
+
+/*
+	// Set up a millisecond counter
+	TIMER0_CR = 0;
+	TIMER0_DATA = 0xFFFF;
+	TIMER0_CR = TIMER_ENABLE | TIMER_CASCADE;
+*/
+
+
+
+	PALETTE[255] = RGB15(0,31,0);
+
+	// Allocate save buffer for game screen
+//	savedBuffer = new u8[320 * 200];
+	displayMode16Bit();
+	
+	memset(BG_GFX, 0, 512 * 256 * 2);	
+	scaledMode = true;
+	scX = 0;
+	scY = 0;
+	subScX = 0;
+	subScY = 0;
+	subScTargetX = 0;
+	subScTargetY = 0;
+	
+	//lcdSwap();
+	POWER_CR &= ~POWER_SWAP_LCDS;
+	
+	frameCount = 0;
+	callback = NULL;
+	
+//	vramSetBankH(VRAM_H_SUB_BG); 
+	
+
+//	// Do text stuff
+	//BG0_CR = BG_MAP_BASE(0) | BG_TILE_BASE(1);
+//	BG0_Y0 = 48;
+	
+	PALETTE[255] = RGB15(31,31,31);//by default font will be rendered with color 255
+	
+	//consoleInit() is a lot more flexible but this gets you up and running quick
+//	consoleInitDefault((u16*)SCREEN_BASE_BLOCK(0), (u16*)CHAR_BASE_BLOCK(1), 16);
+	//consolePrintSet(0, 6);
+	
+	//irqs are nice
+	irqInit();
+//	irqInitHandler();
+	irqSet(IRQ_VBLANK, VBlankHandler);
+	irqSet(IRQ_TIMER0, timerTickHandler);
+	irqSet(IRQ_TIMER2, soundBufferEmptyHandler);
+	
+	irqEnable(IRQ_VBLANK);
+	irqEnable(IRQ_TIMER0);
+	irqEnable(IRQ_TIMER2);
+	
+	
+	// Set up a millisecond timer
+	TIMER0_CR = 0;
+	TIMER0_DATA = (u32) TIMER_FREQ(1000);
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1 | TIMER_IRQ_REQ;	
+	REG_IME = 1;
+
+	PALETTE[255] = RGB15(0,0,31);
+
+	initSprites();
+	
+//	videoSetModeSub(MODE_3_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+	
+	// Convert texture from 24bit 888 to 16bit 1555, remembering to set top bit!
+	u8* srcTex = (u8 *) icons_raw;
+	for (int r = 32 * 160 ; r >= 0; r--) {
+		SPRITE_GFX_SUB[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
+		SPRITE_GFX[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
+	}
+
+	WAIT_CR &= ~(0x0080);
+	REG_WRAM_CNT = 0;
+
+}
+
+
+void setKeyboardIcon(bool enable) {
+	keyboardIcon = enable;
+}
+
+bool getKeyboardIcon() {
+	return keyboardIcon;
+}
+
+
+////////////////////
+// Pen stuff
+////////////////////
+
+
+void penInit() {
+	penDown = false;
+	penHeld = false;
+	penReleased = false;
+	penDownLastFrame = false;
+	penDownSaved = false;
+	penReleasedSaved = false;
+	penDownFrames = 0;
+	consumeKeys();
+}
+
+void penUpdate() {
+
+//	if (getKeysHeld() & KEY_L) consolePrintf("%d, %d   penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1);
+
+	if ((penDownFrames > 1)) {			// Is this right?  Dunno, but it works for me.
+
+		if ((penHeld)) {
+			penHeld = true;
+			penDown = false;
+
+			if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
+				penX = IPC->touchXpx + touchXOffset;
+				penY = IPC->touchYpx + touchYOffset;
+			}
+
+		} else {
+			penDown = true;
+			penHeld = true;
+			penDownSaved = true;
+
+			//if ( (ABS(penX - IPC->touchXpx) < 10) && (ABS(penY - IPC->touchYpx) < 10) ) {
+			if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
+				penX = IPC->touchXpx;
+				penY = IPC->touchYpx;
+			}
+			//}
+		}
+
+	} else {
+		if (penHeld) {
+			penReleased = true;
+			penReleasedSaved = true;
+		} else {
+			penReleased = false;
+		}
+
+		penDown = false;
+		penHeld = false;
+	}
+
+
+	if ((IPC->touchZ1 > 0) || ((penDownFrames == 2)) ) {
+		penDownLastFrame = true;
+		penDownFrames++;
+	} else {
+		penDownLastFrame = false;
+		penDownFrames = 0;
+	}
+	
+}
+
+int leftHandedSwap(int keys) {
+	// Start and select are unchanged
+	if (leftHandedMode) {
+		int result = keys & (~(KEY_R | KEY_L | KEY_Y | KEY_A | KEY_B | KEY_X | KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN));
+		
+		if (keys & KEY_L) result |= KEY_R;
+		if (keys & KEY_R) result |= KEY_L;
+	
+		if (keys & KEY_LEFT) result |= KEY_Y;
+		if (keys & KEY_RIGHT) result |= KEY_A;
+		if (keys & KEY_DOWN) result |= KEY_B;
+		if (keys & KEY_UP) result |= KEY_X;
+	
+		if (keys & KEY_Y) result |= KEY_LEFT;
+		if (keys & KEY_A) result |= KEY_RIGHT;
+		if (keys & KEY_B) result |= KEY_DOWN;
+		if (keys & KEY_X) result |= KEY_UP;
+	
+		return result;
+	} else {
+		return keys;
+	}
+}
+
+void keysUpdate() {
+	scanKeys();
+	keysDownSaved |= leftHandedSwap(keysDown());
+	keysReleasedSaved |= leftHandedSwap(keysUp());
+}
+
+int getKeysDown() {
+	return keysDownSaved;
+}
+
+int getKeysHeld() {
+	return leftHandedSwap(keysHeld());
+}
+
+int getKeysReleased() {
+	return keysReleasedSaved;
+}
+
+void consumeKeys() {
+	keysDownSaved = 0;
+	keysReleasedSaved = 0;
+}
+
+bool getPenDown() {
+	return penDownSaved;
+}
+
+bool getPenHeld() {
+	return penHeld;
+}
+
+bool getPenReleased() {
+	return penReleasedSaved;
+}
+
+void consumePenEvents() {
+	penDownSaved = false;
+	penReleasedSaved = false;
+}
+
+int getPenX() {
+	int x = ((penX * touchScX) >> 8) + touchX;
+	x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x);
+	return x;
+}
+
+int getPenY() {
+	int y = ((penY * touchScY) >> 8) + touchY;
+	y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y);
+	return y;
+}
+
+GLvector getPenPos() {
+	GLvector v;
+	
+	v.x = (penX * inttof32(1)) / SCREEN_WIDTH;
+	v.y = (penY * inttof32(1)) / SCREEN_HEIGHT;
+	
+	return v;
+}
+
+void formatSramOption() {
+	consolePrintf("The following files are present in save RAM:\n");
+	DSSaveFileManager::instance()->listFiles();
+	
+	consolePrintf("\nAre you sure you want to\n");
+	consolePrintf("DELETE all files?\n");
+	consolePrintf("A = Yes, X = No\n");
+	
+	while (true) {
+		if (keysHeld() & KEY_A) {
+			DSSaveFileManager::instance()->formatSram();
+			consolePrintf("SRAM cleared!\n");
+			return;
+		}
+	
+		if (keysHeld() & KEY_X) {
+			consolePrintf("Whew, that was close!\n");
+			return;
+		}
+	}
+}
+
+
+void setIndyFightState(bool st) {
+	indyFightState = st;
+	indyFightRight = true;
+}
+
+bool getIndyFightState() {
+	return indyFightState;
+}
+
+/////////////////
+// GBAMP
+/////////////////
+
+bool GBAMPAvail = false;
+
+void initGBAMP() {	
+	FAT_InitFiles();
+	if (disc_IsInserted()) {
+		GBAMPAvail = true;
+		consolePrintf("Found flash card reader!\n");
+	} else {
+		GBAMPAvail = false;
+		consolePrintf("Flash card reader not found!\n");
+	}
+}
+	 
+bool isGBAMPAvailable() {
+	return GBAMPAvail;
+}
+
+
+
+/////////////////
+// Main
+/////////////////
+
+static const Common::String test("poo", 1, 16);
+
+
+
+int main(void)
+{
+	soundCallback = NULL;
+	
+
+	initHardware();
+	
+	// Let arm9 read cartridge
+	*((u16 *) (0x04000204)) &= ~0x0080;
+	
+	lastCallbackFrame = 0;
+	tweak = 0;
+	
+	indyFightState = false;
+	indyFightRight = true;
+
+	// CPU speed = 67108864
+	// 8 frames = 2946   368.5 bytes per fr
+
+//	playSound(stretch, 47619, false);
+//	playSound(twang, 11010, true);   // 18640
+
+//	bufferSize = 10;
+	bufferRate = 22050;
+	bufferFrame = 0;
+//	bufferSamples = (bufferRate * bufferSize) / 60;
+	bufferSamples = 4096;
+	
+	bufferFirstHalf = false;
+	bufferSecondHalf = true;
+	
+	lastEventFrame = 0;
+	mouseMode = MOUSE_LEFT;
+
+	
+
+	
+	int bytes = (2 * (bufferSamples)) + 100;
+	
+	soundBuffer = (s16 *) malloc(bytes * 2);
+
+
+	soundHiPart = true;
+/*
+	TIMER1_CR = 0;
+	TIMER1_DATA = TIMER_FREQ(bufferRate);
+	TIMER1_CR = TIMER_ENABLE | TIMER_DIV_1;
+	
+	TIMER2_CR = 0;
+	TIMER2_DATA = 0xFFFF - (bufferSamples / 2);
+	TIMER2_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+	*/
+	// 2945 - 2947
+	
+
+	
+//	for (int r = 2946; r < 3000; r++) {
+//		soundBuffer[r] = 30000;
+//	}
+	
+
+	
+	consolePrintf("------------------------\n");
+	consolePrintf("ScummVM DS\n");
+	consolePrintf("Ported by Neil Millstone\n");
+#ifdef DS_SCUMM_BUILD
+	consolePrintf("Version 0.61 build A\n");
+#else
+	consolePrintf("Version 0.61 build B\n");
+#endif
+	consolePrintf("------------------------\n");
+	consolePrintf("L/R + D-pad/pen: Scroll view\n");
+	consolePrintf("D-pad left:  Left mouse button\n");
+	consolePrintf("D-pad right: Right mouse button\n");
+	consolePrintf("D-pad up:    Hover mouse\n");
+	consolePrintf("D-pad down:  Skip dialog line\n");
+	consolePrintf("B button:    Skip cutscenes\n");
+	consolePrintf("Select:		DS Options menu\n");
+	consolePrintf("Start:       Game menu\n");
+	consolePrintf("Y (in game): Toggle console\n");
+	consolePrintf("X:           Toggle keyboard\n");
+	consolePrintf("A:			Swap screens\n");
+	consolePrintf("L + R on bootup: Clear SRAM\n\n");
+	consolePrintf("For a complete poo list see the\n");
+	consolePrintf("help screen.\npoo\n");
+
+
+	for (int r = 0; r < bytes; r++) {
+		soundBuffer[r] = 0;
+	}
+	
+	consolePrintf("length=%d str='%s'\n", test.size(), test.c_str());
+
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	playSound(soundBuffer, (bufferSamples * 2), true);
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	
+
+
+	// Create a file system node to force search for a zip file in GBA rom space
+	DSFileSystemNode* node = new DSFileSystemNode();
+	if (!node->getZip() || (!node->getZip()->isReady())) {
+		// If not found, init CF/SD driver
+		initGBAMP();
+	}
+	delete node;
+
+	
+
+	updateStatus();
+	
+	
+//	OSystem_DS::instance();
+	g_system = new OSystem_DS();
+	assert(g_system);
+
+	if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
+		formatSramOption();
+	}
+
+//	printf("'%s'", Common::ConfigManager::kTransientDomain.c_str());
+	//printf("'%s'", Common::ConfigManager::kApplicationDomain.c_str());
+	
+
+	char* argv[2] = {"/scummvmds", "--config=scummvmb.ini"};
+#ifdef DS_NON_SCUMM_BUILD	
+
+	while (1) {
+		scummvm_main(2, (char **) &argv);
+	}
+#else
+	while (1) {
+		scummvm_main(1, (char **) &argv);
+	}
+#endif
+	
+
+	return 0;
+}
+
+}
+
+int main() {
+	DS::main();
+}
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+
+#include <nds.h>
+
+#include <ARM9/console.h> //basic print funcionality
+
+#include <stdlib.h>
+#include "dsmain.h"
+#include "string.h"
+#include "system.h"
+#include "osystem_ds.h"
+#include "icons_raw.h"
+#include "gba_nds_fat.h"
+#include "disc_io.h"
+#include "config-manager.h"
+#include "engines/scumm/scumm.h"
+#include "keyboard_raw.h"
+#include "keyboard_pal_raw.h"
+#define V16(a, b) ((a << 12) | b)
+#include "touchkeyboard.h"
+#include "registers_alt.h"
+//#include "compact_flash.h"
+#include "dsoptions.h"
+
+namespace DS {
+
+// From console.c in NDSLib
+
+//location of cursor
+extern u8 row;
+extern u8 col;
+
+// Mouse mode
+enum MouseMode {
+	MOUSE_LEFT, MOUSE_RIGHT, MOUSE_HOVER, MOUSE_NUM_MODES
+};
+
+// Defines
+#define FRAME_TIME 17
+#define SCUMM_GAME_HEIGHT 142
+#define SCUMM_GAME_WIDTH 232
+
+int textureID;
+u16* texture;
+
+int frameCount;
+int currentTimeMillis;
+
+// Timer Callback
+int callbackInterval;
+int callbackTimer;
+OSystem::TimerProc callback;
+
+// Scaled
+bool scaledMode;
+int scX;
+int scY;
+
+int subScX;
+int subScY;
+int subScTargetX;
+int subScTargetY;
+int subScreenWidth = SCUMM_GAME_WIDTH;
+int subScreenHeight = SCUMM_GAME_HEIGHT;
+int subScreenScale = 256;
+
+
+
+// Sound
+int bufferSize;
+s16* soundBuffer;
+int bufferFrame;
+int bufferRate;
+int bufferSamples;
+bool soundHiPart;
+
+// Events
+int lastEventFrame;
+bool indyFightState;
+bool indyFightRight;
+
+OSystem::SoundProc soundCallback;
+void* soundParam;
+int lastCallbackFrame;
+bool bufferFirstHalf;
+bool bufferSecondHalf;
+
+// Saved buffers
+u8* savedBuffer = NULL;
+bool highBuffer;
+bool displayModeIs8Bit;
+
+// Game id
+u8 gameID;
+
+bool consoleEnable = true;
+bool gameScreenSwap = false;
+
+MouseMode mouseMode;
+
+// Sprites
+SpriteEntry sprites[128];
+SpriteEntry spritesMain[128];
+int tweak;
+
+// Shake
+int shakePos = 0;
+
+// Keyboard
+bool keyboardEnable = false;
+bool leftHandedMode = false;
+bool keyboardIcon = false;
+
+// Touch
+int touchScX, touchScY, touchX, touchY;
+
+// Dragging
+int dragStartX, dragStartY;
+bool dragging = false;
+int dragScX, dragScY;
+
+// Interface styles
+char gameName[32];
+
+// 8-bit surface size
+int gameWidth = 320;
+int gameHeight = 200;
+
+enum controlType {
+	CONT_SCUMM_ORIGINAL,
+	CONT_SCUMM_SAMNMAX,
+	CONT_SKY,
+	CONT_SIMON,
+};
+
+struct gameListType {
+	char 			gameId[16];
+	controlType 	control;
+};
+
+#define NUM_SUPPORTED_GAMES 15
+
+gameListType gameList[NUM_SUPPORTED_GAMES] = {
+	// Unknown game - use normal SCUMM controls
+	{"unknown", 	CONT_SCUMM_ORIGINAL},
+	
+	// SCUMM games
+	{"maniac",		CONT_SCUMM_ORIGINAL},
+	{"zak",			CONT_SCUMM_ORIGINAL},
+	{"loom",		CONT_SCUMM_ORIGINAL},
+	{"indy3",		CONT_SCUMM_ORIGINAL},
+	{"atlantis",	CONT_SCUMM_ORIGINAL},
+	{"monkey",		CONT_SCUMM_ORIGINAL},
+	{"monkey2",		CONT_SCUMM_ORIGINAL},
+	{"tentacle",	CONT_SCUMM_ORIGINAL},
+	{"samnmax",		CONT_SCUMM_SAMNMAX},
+	
+	// Non-SCUMM games
+	{"sky",			CONT_SKY},
+	{"simon1",		CONT_SIMON},
+	{"simon2",		CONT_SIMON},
+	{"gob1",		CONT_SCUMM_ORIGINAL},
+	{"queen",		CONT_SCUMM_ORIGINAL}
+};
+
+gameListType* currentGame = NULL;
+
+// Stylus
+#define ABS(x) ((x)>0?(x):-(x))
+
+bool penDown;
+bool penHeld;
+bool penReleased;
+bool penDownLastFrame;
+f32 penX, penY;
+int keysDownSaved;
+int keysReleasedSaved;
+
+bool penDownSaved;
+bool penReleasedSaved;
+int penDownFrames;
+int touchXOffset = 0;
+int touchYOffset = 0;
+
+u16 savedPalEntry255 = RGB15(31, 31, 31);
+
+
+extern "C" int scummvm_main(int argc, char *argv[]);
+void updateStatus();
+
+TransferSound soundControl;
+
+//plays an 8 bit mono sample at 11025Hz
+void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate)
+{
+	
+	if (!IPC->soundData) {
+		soundControl.count = 0;
+	}
+	
+	soundControl.data[soundControl.count].data = data;
+	soundControl.data[soundControl.count].len = length | (loop? 0x80000000: 0x00000000);
+	soundControl.data[soundControl.count].rate = rate;		// 367 samples per frame
+	soundControl.data[soundControl.count].pan = 64;
+	soundControl.data[soundControl.count].vol = 127;
+	soundControl.data[soundControl.count].format = adpcm? 2: 0;
+
+	soundControl.count++;
+
+	DC_FlushAll();
+	IPC->soundData = &soundControl;
+}
+
+void stopSound(int channel) {
+	playSound(NULL, 0, false, false, -channel);
+}
+
+void updateOAM() {
+	DC_FlushAll();
+    dmaCopy(sprites, OAM_SUB, 128 * sizeof(SpriteEntry));
+    dmaCopy(spritesMain, OAM, 128 * sizeof(SpriteEntry));
+}
+
+void setGameSize(int width, int height) {
+	gameWidth = width;
+	gameHeight = height;
+}
+
+int getGameWidth() {
+	return gameWidth;
+}
+
+int getGameHeight() {
+	return gameHeight;
+}
+
+void initSprites() {
+	for(int i = 0; i < 128; i++) {
+	   sprites[i].attribute[0] = ATTR0_DISABLED;
+	   sprites[i].attribute[1] = 0;
+	   sprites[i].attribute[2] = 0;
+	   sprites[i].attribute[3] = 0;
+    }
+	
+	for(int i = 0; i < 128; i++) {
+	   spritesMain[i].attribute[0] = ATTR0_DISABLED;
+	   spritesMain[i].attribute[1] = 0;
+	   spritesMain[i].attribute[2] = 0;
+	   spritesMain[i].attribute[3] = 0;
+    }
+	
+	updateOAM();
+}
+
+
+void saveGameBackBuffer() {
+#ifdef DISABLE_SCUMM
+	if (savedBuffer == NULL) savedBuffer = new u8[gameWidth * gameHeight];
+	for (int r = 0; r < 200; r++) {
+		memcpy(savedBuffer + (r * gameWidth), ((u8 *) (get8BitBackBuffer())) + (r * 512), gameWidth);
+	}
+#endif
+}
+
+void restoreGameBackBuffer() {
+#ifdef DISABLE_SCUMM
+	if (savedBuffer) {
+		for (int r = 0; r < 200; r++) {
+			memcpy(((u8 *) (BG_GFX_SUB)) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+			memcpy(((u8 *) (get8BitBackBuffer())) + (r * 512), savedBuffer + (r * gameWidth), gameWidth);
+		}
+		delete savedBuffer;
+		savedBuffer = NULL;
+	}
+#endif
+
+#ifndef DISABLE_SCUMM	
+	memset(get8BitBackBuffer(), 0, 512 * 256);
+	memset(BG_GFX_SUB, 0, 512 * 256);
+	if (Scumm::g_scumm) {
+		Scumm::g_scumm->markRectAsDirty(Scumm::kMainVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+		Scumm::g_scumm->markRectAsDirty(Scumm::kTextVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+		Scumm::g_scumm->markRectAsDirty(Scumm::kVerbVirtScreen, 0, gameWidth - 1, 0, gameHeight - 1, 1);
+	}
+#endif
+
+}
+
+
+void initGame() {
+	// This is a good time to check for left handed mode since the mode change is done as the game starts.
+	// There's probably a better way, but hey.
+//	consolePrintf("initing game\n");
+
+	setOptions();
+
+	//strcpy(gameName, ConfMan.getActiveDomain().c_str());
+	strcpy(gameName, ConfMan.get("gameid").c_str());
+//	consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
+
+	currentGame = &gameList[0];		// Default game
+	
+	for (int r = 0; r < NUM_SUPPORTED_GAMES; r++) {
+		if (!stricmp(gameName, gameList[r].gameId)) {
+			currentGame = &gameList[r];
+//			consolePrintf("Game list num: %d\n", currentGame);
+		}
+	}
+	
+
+}
+
+void setLeftHanded(bool enable) {
+	leftHandedMode = enable;
+}
+
+void setTouchXOffset(int x) {
+	touchXOffset = x;
+}
+
+void setTouchYOffset(int y) {
+	touchYOffset = y;
+}
+
+void setUnscaledMode(bool enable) {
+	scaledMode = !enable;
+}
+
+void displayMode8Bit() {
+
+	u16 buffer[32 * 32];
+	
+	setKeyboardEnable(false);
+
+	if (!displayModeIs8Bit) {
+		for (int r = 0; r < 32 * 32; r++) {
+			buffer[r] = ((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r];
+		}
+	}
+	
+	
+
+	videoSetMode(MODE_5_2D | (consoleEnable? DISPLAY_BG0_ACTIVE: 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); 
+	videoSetModeSub(MODE_3_2D /*| DISPLAY_BG0_ACTIVE*/ | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+
+	vramSetBankA(VRAM_A_MAIN_BG_0x6000000);
+	vramSetBankB(VRAM_B_MAIN_BG_0x6020000);
+
+	vramSetBankC(VRAM_C_SUB_BG_0x6200000);
+	vramSetBankD(VRAM_D_MAIN_BG_0x6040000);
+	
+	vramSetBankH(VRAM_H_LCD);
+
+	BG3_CR = BG_BMP8_512x256 | BG_BMP_BASE(8);
+	
+	
+	
+	BG3_XDX = (int) (((float) (gameWidth) / 256.0f) * 256);
+    BG3_XDY = 0;
+    BG3_YDX = 0;
+    BG3_YDY = (int) ((200.0f / 192.0f) * 256);
+
+	SUB_BG3_CR = BG_BMP8_512x256;
+	
+	
+	
+	SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
+    SUB_BG3_XDY = 0;
+    SUB_BG3_YDX = 0;
+    SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);
+
+
+	// Do text stuff
+	BG0_CR = BG_MAP_BASE(0) | BG_TILE_BASE(1);
+	BG0_Y0 = 0;
+	
+	// Restore palette entry used by text in the front-end	
+	PALETTE_SUB[255] = savedPalEntry255;
+	
+	consoleInitDefault((u16*)SCREEN_BASE_BLOCK(0), (u16*)CHAR_BASE_BLOCK(1), 16);
+	consolePrintSet(0, 23);
+	
+	if (!displayModeIs8Bit) {
+		for (int r = 0; r < 32 * 32; r++) {
+			((u16 *) SCREEN_BASE_BLOCK(0))[r] = buffer[r];
+		}
+//		dmaCopyHalfWords(3, (u16 *) SCREEN_BASE_BLOCK(0), buffer, 32 * 32 * 2);
+	}
+	
+	
+	if (!displayModeIs8Bit) restoreGameBackBuffer();
+	displayModeIs8Bit = true;
+	
+	POWER_CR &= ~POWER_SWAP_LCDS;
+	
+	keyboardEnable = false;
+	initGame();
+	
+}
+
+void setGameID(int id) {
+	gameID = id;
+}
+
+void dummyHandler() {
+	REG_IF = IRQ_VBLANK;
+}
+
+void checkSleepMode() {
+	if (IPC->performArm9SleepMode) {
+	
+		consolePrintf("ARM9 Entering sleep mode\n");
+		
+		int intSave = REG_IE;
+		irqSet(IRQ_VBLANK, dummyHandler);
+//		int irqHandlerSave = (int) IRQ_HANDLER;
+		REG_IE = IRQ_VBLANK;
+		//IRQ_HANDLER = dummyHandler;
+		
+		int powerSave = POWER_CR;
+		POWER_CR &= ~POWER_ALL;
+		
+		while (IPC->performArm9SleepMode) {
+			swiWaitForVBlank();
+		}
+		
+		POWER_CR = powerSave;
+//		IRQ_HANDLER = (void (*)()) irqHandlerSave;
+		irqSet(IRQ_VBLANK, VBlankHandler);
+		REG_IE = intSave;
+
+		consolePrintf("ARM9 Waking from sleep mode\n");
+	}
+}
+
+void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor) {
+	if (currentGame->control != CONT_SCUMM_SAMNMAX)
+		return;
+
+	uint16 border = RGB15(24,24,24) | 0x8000;
+	
+	
+	int off = 48*64;
+	memset(SPRITE_GFX_SUB+off, 0, 64*64*2);
+	
+	int pos = 190 - (w+2);
+	
+
+	
+	// make border
+	for (uint i=0; i<w+2; i++) {
+		SPRITE_GFX_SUB[off+i] = border;
+		SPRITE_GFX_SUB[off+(31)*64+i] = border;
+	}
+	for (uint i=1; i<31; i++) {
+		SPRITE_GFX_SUB[off+(i*64)] = border;
+		SPRITE_GFX_SUB[off+(i*64)+(w+1)] = border;
+	}
+	
+	int offset = (32 - h) >> 1;
+
+	for (uint y=0; y<h; y++) {
+		for (uint x=0; x<w; x++) {
+			int color = icon[y*w+x];
+			if (color == keycolor) {
+				SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = 0x8000; // black background
+			} else {
+				SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = BG_PALETTE[color] | 0x8000;
+			}
+		}
+	}
+
+	sprites[1].attribute[0] = ATTR0_BMP | 150;
+	sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
+	sprites[1].attribute[2] = ATTR2_ALPHA(1) | 48;
+}
+
+
+
+
+void displayMode16Bit() {
+
+	u16 buffer[32 * 32 * 2];
+
+
+	if (displayModeIs8Bit) {
+		saveGameBackBuffer();
+		for (int r = 0; r < 32 * 32; r++) {
+			buffer[r] = ((u16 *) SCREEN_BASE_BLOCK(0))[r];
+		}
+	}
+
+
+	videoSetMode(MODE_5_2D | /*DISPLAY_BG0_ACTIVE |*/ DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); 
+	videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE |/* DISPLAY_BG1_ACTIVE |*/ DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+
+	vramSetBankA(VRAM_A_MAIN_BG);
+	vramSetBankB(VRAM_B_MAIN_BG);
+	vramSetBankC(VRAM_C_MAIN_BG);
+	vramSetBankD(VRAM_D_MAIN_BG);
+	vramSetBankH(VRAM_H_SUB_BG);
+
+	BG3_CR = BG_BMP16_512x256;
+	highBuffer = false;
+	
+	BG3_XDX = (int) (1.25f * 256);
+    BG3_XDY = 0;
+    BG3_YDX = 0;
+    BG3_YDY = (int) ((200.0f / 192.0f) * 256);
+
+	memset(BG_GFX, 0, 512 * 256 * 2);
+	
+	savedPalEntry255 = PALETTE_SUB[255];
+	PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
+
+	// Do text stuff
+	SUB_BG0_CR = BG_MAP_BASE(4) | BG_TILE_BASE(0);
+	SUB_BG0_Y0 = 0;
+
+	consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(4), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
+
+	if (displayModeIs8Bit) {
+		//dmaCopyHalfWords(3, (u16 *) SCREEN_BASE_BLOCK_SUB(0), buffer, 32 * 32 * 2);
+		for (int r = 0; r < 32 * 32; r++) {
+			((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r] = buffer[r];
+		}
+	}
+
+	consolePrintSet(0, 23);
+	consolePrintf("\n");
+	
+	// Show keyboard
+	SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
+	//drawKeyboard(1, 12);
+	
+	POWER_CR &= ~POWER_SWAP_LCDS;
+
+
+
+	displayModeIs8Bit = false;
+}
+
+
+void displayMode16BitFlipBuffer() {
+	if (!displayModeIs8Bit) {
+		u16* back = get16BitBackBuffer();
+	
+//		highBuffer = !highBuffer;
+//		BG3_CR = BG_BMP16_512x256 |	BG_BMP_RAM(highBuffer? 1: 0);
+		
+		for (int r = 0; r < 512 * 256; r++) {
+			*(BG_GFX + r) = *(back + r);
+		}
+	}
+}
+
+void setShakePos(int shakePos) {
+	shakePos = shakePos;
+}
+
+
+u16* get16BitBackBuffer() {
+	return BG_GFX + 0x20000;
+}
+
+u16* get8BitBackBuffer() {
+	return BG_GFX + 0x10000;		// 16bit qty!
+}
+
+void setSoundProc(OSystem::SoundProc proc, void* param) {
+//	consolePrintf("Set sound callback");
+	soundCallback = proc;
+	soundParam = param;
+}
+
+// The sound system in ScummVM seems to always return stereo interleaved samples.
+// Here, I'm treating an 11Khz stereo stream as a 22Khz mono stream, which works sorta ok, but is
+// a horrible bodge.  Any advice on how to change the engine to output mono would be greatly
+// appreciated.
+void doSoundCallback() {
+	if ((soundCallback)) {
+		lastCallbackFrame = frameCount;
+		
+		for (int r = IPC->playingSection; r < IPC->playingSection + 4; r++) {
+			int chunk = r & 3;
+			
+			if (IPC->fillNeeded[chunk]) {
+				IPC->fillNeeded[chunk] = false;
+				DC_FlushAll();
+				soundCallback(soundParam, (byte *) (soundBuffer + ((bufferSamples >> 2) * chunk)), bufferSamples >> 1);
+				IPC->fillNeeded[chunk] = false;
+				DC_FlushAll();
+			}
+		
+		}
+		
+	}
+}
+
+void doTimerCallback() {
+	if (callback) {
+		if (callbackTimer <= 0) {
+			callbackTimer += callbackInterval;
+			callback(callbackInterval);
+		}	
+	}
+}
+
+void soundUpdate() {
+	if ((bufferFrame == 0)) {
+//		playSound(soundBuffer, (bufferSamples * 2), true);
+	}
+//	consolePrintf("%x\n", IPC->test);
+	
+	
+	if (bufferFrame == 0) {
+//		bufferFirstHalf = true;
+	}	
+	if (bufferFrame == bufferSize >> 1) {
+	//bufferSecondHalf = true;
+	}	
+	
+	bufferFrame++;
+	if (bufferFrame == bufferSize) {
+		bufferFrame = 0;
+	}
+}
+
+void memoryReport() {
+	int r = 0;
+	int* p;
+	do {
+		p = (int *) malloc(r * 8192);
+		free(p);
+		r++;		
+	} while ((p) && (r < 512));
+	
+	int t = -1;
+	void* block[1024];
+	do {
+		t++;
+		block[t] = (int *) malloc(4096);
+	} while ((t < 1024) && (block[t]));		
+	
+	for (int q = 0; q < t; q++) {
+		free(block[q]);
+	}
+	
+	consolePrintf("Free: %dK, Largest: %dK\n", t * 4, r * 8);
+}
+
+
+void addIndyFightingKeys() {
+	OSystem_DS* system = OSystem_DS::instance();
+	OSystem::Event event;
+
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.flags = 0;
+
+	if ((getKeysDown() & KEY_L)) {
+		indyFightRight = false;
+	}
+
+	if ((getKeysDown() & KEY_R)) {
+		indyFightRight = true;
+	}
+
+	if ((getKeysDown() & KEY_UP)) {
+		event.kbd.keycode = '8';
+		event.kbd.ascii = '8';
+		system->addEvent(event);
+	}
+	if ((getKeysDown() & KEY_LEFT)) {
+		event.kbd.keycode = '4';
+		event.kbd.ascii = '4';
+		system->addEvent(event);
+	}
+	if ((getKeysDown() & KEY_RIGHT)) {
+		event.kbd.keycode = '6';
+		event.kbd.ascii = '6';
+		system->addEvent(event);
+	}	
+	if ((getKeysDown() & KEY_DOWN)) {
+		event.kbd.keycode = '2';
+		event.kbd.ascii = '2';
+		system->addEvent(event);
+	}
+	
+	if (indyFightRight) {
+	
+		if ((getKeysDown() & KEY_X)) {
+			event.kbd.keycode = '9';
+			event.kbd.ascii = '9';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_A)) {
+			event.kbd.keycode = '6';
+			event.kbd.ascii = '6';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_B)) {
+			event.kbd.keycode = '3';
+			event.kbd.ascii = '3';
+			system->addEvent(event);
+		}	
+
+	} else {
+
+		if ((getKeysDown() & KEY_X)) {
+			event.kbd.keycode = '7';
+			event.kbd.ascii = '7';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_A)) {
+			event.kbd.keycode = '4';
+			event.kbd.ascii = '4';
+			system->addEvent(event);
+		}
+		if ((getKeysDown() & KEY_B)) {
+			event.kbd.keycode = '1';
+			event.kbd.ascii = '1';
+			system->addEvent(event);
+		}	
+	
+	}
+	
+	
+	if ((getKeysDown() & KEY_Y)) {
+		event.kbd.keycode = '5';
+		event.kbd.ascii = '5';
+		system->addEvent(event);
+	}
+} 			
+
+
+void setKeyboardEnable(bool en) {
+	if (en == keyboardEnable) return;
+	keyboardEnable = en;
+	u16* backupBank = (u16 *) 0x6040000;
+
+	if (keyboardEnable) {
+
+
+		DS::drawKeyboard(1, 12, backupBank);
+		
+		
+		SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
+
+		if (displayModeIs8Bit) {
+			SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE;	// Turn on keyboard layer
+			SUB_DISPLAY_CR &= ~DISPLAY_BG3_ACTIVE;	// Turn off game layer
+		} else {
+			SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE;	// Turn on keyboard layer
+			SUB_DISPLAY_CR &= ~DISPLAY_BG0_ACTIVE;	// Turn off console layer
+		}
+		lcdSwap();
+	} else {
+
+
+		// Restore the palette that the keyboard has used
+		for (int r = 0; r < 256; r++) {
+			BG_PALETTE_SUB[r] = BG_PALETTE[r];
+		}
+		
+		
+		//restoreVRAM(1, 12, backupBank);
+		
+		if (displayModeIs8Bit) {
+			// Copy the sub screen VRAM from the top screen - they should always be
+			// the same.
+			for (int r = 0; r < (512 * 256) >> 1; r++) {
+				BG_GFX_SUB[r] = get8BitBackBuffer()[r];
+			}
+			
+			SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE;	// Turn off keyboard layer
+			SUB_DISPLAY_CR |= DISPLAY_BG3_ACTIVE;	// Turn on game layer
+		} else {
+			SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE;	// Turn off keyboard layer
+			SUB_DISPLAY_CR |= DISPLAY_BG0_ACTIVE;	// Turn on console layer
+		}
+		
+		lcdSwap();
+	}
+}
+
+bool getKeyboardEnable() {
+	return keyboardEnable;
+}
+
+bool getIsDisplayMode8Bit() {
+	return displayModeIs8Bit;
+}
+
+void addEventsToQueue() {
+	OSystem_DS* system = OSystem_DS::instance();
+	OSystem::Event event;
+
+	
+
+	
+	if (system->isEventQueueEmpty()) {
+
+/*
+		if (getKeysDown() & KEY_L) {
+			tweak--;
+			consolePrintf("Tweak: %d\n", tweak);
+			IPC->tweakChanged = true;
+		}
+		
+
+		if (getKeysDown() & KEY_R) {
+			tweak++;
+			consolePrintf("Tweak: %d\n", tweak);
+			IPC->tweakChanged = true;
+		}
+	*/
+		if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
+			memoryReport();
+		}
+
+		if (displayModeIs8Bit) {
+
+			if (!indyFightState) {
+
+				
+				if ((getKeysDown() & KEY_B) && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+		//			consolePrintf("Pressing Esc");
+		
+					event.type = OSystem::EVENT_KEYDOWN;
+					event.kbd.keycode = 27;		
+					event.kbd.ascii = 27;		
+					event.kbd.flags = 0;
+					system->addEvent(event);
+				}
+		
+			}
+			
+		
+			
+			if ((!getIndyFightState()) && (getKeysDown() & KEY_Y)) {
+				consoleEnable = !consoleEnable;
+				if (displayModeIs8Bit) {
+					displayMode8Bit();
+				} else {
+					displayMode16Bit();
+				}
+			}
+	
+	
+			if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState())) {
+
+				if ((getKeysDown() & KEY_A) && (!indyFightState)) {
+					gameScreenSwap = !gameScreenSwap;
+				}
+	
+				if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) {
+					if (getKeysDown() & KEY_LEFT) {
+						mouseMode = MOUSE_LEFT;
+					}
+					if (getKeysDown() & KEY_RIGHT) {
+						if (currentGame->control != CONT_SCUMM_SAMNMAX) {
+							mouseMode = MOUSE_RIGHT;
+						} else {
+							// If we're playing sam and max, click and release the right mouse
+							// button to change verb
+							OSystem::Event event;
+		
+							event.type = OSystem::EVENT_RBUTTONDOWN;
+							event.mouse = Common::Point(getPenX(), getPenY());
+							system->addEvent(event);
+		
+							event.type = OSystem::EVENT_RBUTTONUP;
+							system->addEvent(event);
+						}
+					}
+					if (getKeysDown() & KEY_UP) {
+						mouseMode = MOUSE_HOVER;
+					}
+				}
+	
+					
+				
+			}
+
+			if ((getKeysDown() & KEY_SELECT)) {
+				//scaledMode = !scaledMode;
+				//scY = 4;
+				showOptionsDialog();
+			}
+
+			
+		}
+	
+		if (!getIndyFightState() && !((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (getKeysDown() & KEY_X)) {
+			setKeyboardEnable(!keyboardEnable);
+		}
+		
+		updateStatus();			
+		
+		OSystem::Event event;
+
+		if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+			event.type = OSystem::EVENT_MOUSEMOVE;
+			event.mouse = Common::Point(getPenX(), getPenY());
+			system->addEvent(event);
+			//consolePrintf("x=%d   y=%d  \n", getPenX(), getPenY());
+		}
+	
+		if (!keyboardEnable) {
+			if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
+					if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {	
+						event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? OSystem::EVENT_LBUTTONDOWN: OSystem::EVENT_RBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+					
+					if (getPenReleased()) {
+						event.type = mouseMode == MOUSE_LEFT? OSystem::EVENT_LBUTTONUP: OSystem::EVENT_RBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+			} else {
+				// In hover mode, D-pad left and right click the mouse when the pen is on the screen
+	
+				if (getPenHeld()) {
+					if (getKeysDown() & KEY_LEFT) {
+						event.type = OSystem::EVENT_LBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+				/*	if (getKeysReleased() & KEY_LEFT) {
+						event.type = OSystem::EVENT_LBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}*/
+	
+					if (getKeysDown() & KEY_RIGHT) {
+						event.type = OSystem::EVENT_RBUTTONDOWN;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}
+					/*if (getKeysReleased() & KEY_RIGHT) {
+						event.type = OSystem::EVENT_RBUTTONUP;
+						event.mouse = Common::Point(getPenX(), getPenY());
+						system->addEvent(event);
+					}*/
+				}
+			}
+			
+			if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))  && (displayModeIs8Bit)) {
+				// Controls specific to the control method
+			
+			
+				if (currentGame->control == CONT_SKY) {
+					// Extra controls for Benieth a Steel Sky
+					if ((getKeysDown() & KEY_DOWN)) {
+						penY = 0;
+						penX = 0;		// Show inventory by moving mouse onto top line
+					}
+				}
+
+				if (currentGame->control == CONT_SIMON) {
+					// Extra controls for Simon the Sorcerer
+					if ((getKeysDown() & KEY_DOWN)) {
+						OSystem::Event event;
+					
+						event.type = OSystem::EVENT_KEYDOWN;
+						event.kbd.keycode = '#';		// F10 or # - show hotspots
+						event.kbd.ascii = '#';
+						event.kbd.flags = 0;
+						system->addEvent(event);
+//						consolePrintf("F10\n");
+					}
+				}
+	
+				if (currentGame->control == CONT_SCUMM_ORIGINAL) {
+					// Extra controls for Scumm v1-5 games
+					if ((getKeysDown() & KEY_DOWN)) {
+						OSystem::Event event;
+					
+						event.type = OSystem::EVENT_KEYDOWN;
+						event.kbd.keycode = '.';		// Full stop - skips current dialogue line
+						event.kbd.ascii = '.';
+						event.kbd.flags = 0;
+						system->addEvent(event);
+					}
+					
+					if (indyFightState) {
+						addIndyFightingKeys();
+					}
+					
+				}
+				
+			}
+		}
+		
+		if (!displayModeIs8Bit) {
+			// Front end controls
+			
+			if (leftHandedSwap(getKeysDown()) & KEY_UP) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_UP;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+
+			if (leftHandedSwap(getKeysDown()) & KEY_DOWN) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_DOWN;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+
+			if (leftHandedSwap(getKeysDown()) & KEY_A) {
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.keycode = SDLK_RETURN;
+				event.kbd.ascii = 0;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+			}
+		
+		}
+
+		
+		if ((getKeysDown() & KEY_START)) {
+			event.type = OSystem::EVENT_KEYDOWN;
+			event.kbd.keycode = 319;		// F5
+			event.kbd.ascii = 319;
+			event.kbd.flags = 0;
+			system->addEvent(event);
+/*
+			event.type = OSystem::EVENT_KEYUP;
+			event.kbd.keycode = 319;		// F5
+			event.kbd.ascii = 319;
+			system->addEvent(event);*/
+			
+//			consolePrintf("Pressing F5");
+		}
+
+		
+		if (keyboardEnable) {
+			DS::addKeyboardEvents();
+		}
+		
+		consumeKeys();
+		
+		consumePenEvents();
+
+	}
+}
+
+void updateStatus() {
+	int offs;
+
+	if (displayModeIs8Bit) {
+		switch (mouseMode) {
+			case MOUSE_LEFT: {
+				offs = 16;
+				break;
+			}
+			case MOUSE_RIGHT: {
+				offs = 32;
+				break;
+			}
+			case MOUSE_HOVER: {
+				offs = 0;
+				break;
+			}
+			default: {
+				// Nothing!
+				offs = 0;
+				break;
+			}
+		}
+	
+		
+		sprites[0].attribute[0] = ATTR0_BMP | 150; 
+		sprites[0].attribute[1] = ATTR1_SIZE_32 | 208;
+		sprites[0].attribute[2] = ATTR2_ALPHA(1)| offs;
+	
+		if (indyFightState) {
+			sprites[2].attribute[0] = ATTR0_BMP | 150; 
+			sprites[2].attribute[1] = ATTR1_SIZE_32 | (190 - 32) | (indyFightRight? 0: ATTR1_FLIP_X);
+			sprites[2].attribute[2] = ATTR2_ALPHA(1)| 48;
+		} else {
+			sprites[2].attribute[0] = ATTR0_DISABLED; 
+			sprites[2].attribute[1] = 0;
+			sprites[2].attribute[2] = 0;
+		}
+	} else {
+		sprites[0].attribute[0] = ATTR0_DISABLED; 
+		sprites[1].attribute[0] = ATTR0_DISABLED; 
+		sprites[2].attribute[0] = ATTR0_DISABLED; 
+		sprites[3].attribute[0] = ATTR0_DISABLED; 
+	}
+
+	if ((keyboardIcon) && (!keyboardEnable) && (!displayModeIs8Bit)) {
+		spritesMain[0].attribute[0] = ATTR0_BMP | 160;
+		spritesMain[0].attribute[1] = ATTR1_SIZE_32 | 0;
+		spritesMain[0].attribute[2] = ATTR2_ALPHA(1) | 64;
+	} else {
+		spritesMain[0].attribute[0] = ATTR0_DISABLED;
+		spritesMain[0].attribute[1] = 0;
+		spritesMain[0].attribute[2] = 0;
+		spritesMain[0].attribute[3] = 0;
+	}
+
+}
+
+void soundBufferEmptyHandler() {
+	REG_IF = IRQ_TIMER2;
+
+	if (soundHiPart) {
+//		bufferSecondHalf = true;
+	} else {
+//		bufferFirstHalf = true;
+	}
+	
+	soundHiPart = !soundHiPart;
+}
+
+void setMainScreenScroll(int x, int y) {
+	if (gameScreenSwap) {
+		SUB_BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		SUB_BG3_CY = y;
+	} else {
+		BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		BG3_CY = y;
+		
+		touchX = x >> 8;
+		touchY = y >> 8;
+	}
+}
+
+void setMainScreenScale(int x, int y) {
+	if (gameScreenSwap) {
+		SUB_BG3_XDX = x;
+		SUB_BG3_XDY = 0;
+		SUB_BG3_YDX = 0;
+		SUB_BG3_YDY = y;
+	} else {
+		BG3_XDX = x;
+		BG3_XDY = 0;
+		BG3_YDX = 0;
+		BG3_YDY = y;
+		
+		touchScX = x;
+		touchScY = y;
+	}
+}
+
+void setZoomedScreenScroll(int x, int y) {
+	if (gameScreenSwap) {
+		BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		BG3_CY = y;
+		
+		touchX = x >> 8;
+		touchY = y >> 8;
+	} else {
+		SUB_BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
+		SUB_BG3_CY = y;
+	}
+}
+
+void setZoomedScreenScale(int x, int y) {
+	if (gameScreenSwap) {
+		BG3_XDX = x;
+		BG3_XDY = 0;
+		BG3_YDX = 0;
+		BG3_YDY = y;
+
+		touchScX = x;
+		touchScY = y;
+	} else {
+		SUB_BG3_XDX = x;
+		SUB_BG3_XDY = 0;
+		SUB_BG3_YDX = 0;
+		SUB_BG3_YDY = y;
+	}
+}
+
+void VBlankHandler(void) {
+//	BG_PALETTE[0] = RGB15(31, 31, 31);
+//	if (*((int *) (0x023FFF00)) != 0xBEEFCAFE) {
+	//	consolePrintf("Guard band overwritten!");
+//  }
+
+//	consolePri ntf("X:%d Y:%d\n", getPenX(), getPenY());
+
+
+	IPC->tweak = tweak;
+	soundUpdate();
+
+
+	
+
+	if ((!gameScreenSwap) && (!(getKeysHeld() & KEY_L) && !(getKeysHeld() & KEY_R))) {
+		if (currentGame) {
+			if (currentGame->control != CONT_SCUMM_SAMNMAX) {
+				if (getPenHeld() && (getPenY() < SCUMM_GAME_HEIGHT)) {
+					setTopScreenTarget(getPenX(), getPenY());
+				}
+			} else {
+				if (getPenHeld()) {
+					setTopScreenTarget(getPenX(), getPenY());
+				}
+			}
+		}
+	}
+	
+
+	penUpdate();
+	keysUpdate();
+
+
+	frameCount++;
+	
+
+
+	if (callback) {
+		callbackTimer -= FRAME_TIME;
+	}
+	
+	if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+	
+		if ((!dragging) && (getPenHeld()) && (penDownFrames > 5)) {
+			dragging = true;
+			dragStartX = penX;
+			dragStartY = penY;
+			
+			if (gameScreenSwap) {
+				dragScX = subScTargetX;
+				dragScY = subScTargetY;
+			} else {
+				dragScX = scX;
+				dragScY = scY;				
+			}	
+			
+			
+		}
+		
+		if ((dragging) && (!getPenHeld())) {
+			dragging = false;
+		}
+		
+		if (dragging) {
+		
+			if (gameScreenSwap) {
+				subScTargetX = dragScX + ((dragStartX - penX) << 8);
+				subScTargetY = dragScY + ((dragStartY - penY) << 8);
+			} else {
+				scX = dragScX + ((dragStartX - penX));
+				scY = dragScY + ((dragStartY - penY));
+			}
+			
+//			consolePrintf("X:%d Y:%d\n", dragStartX - penX, dragStartY - penY);
+		}
+	}	
+	
+	
+/*	if ((frameCount & 1) == 0) {
+		SUB_BG3_CX = subScX;
+	} else {
+		SUB_BG3_CX = subScX + 64;
+	}
+	
+	SUB_BG3_CY = subScY + (shakePos << 8);*/
+
+	/*SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
+    SUB_BG3_XDY = 0;
+    SUB_BG3_YDX = 0;
+    SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/
+	
+	
+	if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+		if ((getKeysHeld() & KEY_A) && (subScreenScale < 256)) {
+			subScreenScale += 3;
+		}
+		
+		if ((getKeysHeld() & KEY_B) && (subScreenScale > 128)) {
+			subScreenScale -=3;
+		}
+		
+		int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8);
+		int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8);
+		
+		subScreenWidth = SCUMM_GAME_WIDTH * subScreenScale >> 8;
+		subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8;
+		
+		subScTargetX = xCenter - ((subScreenWidth >> 1) << 8);
+		subScTargetY = yCenter - ((subScreenHeight >> 1) << 8);
+		
+
+		
+
+		if (subScTargetX < 0) subScTargetX = 0;
+		if (subScTargetX > (gameWidth - subScreenWidth) << 8) subScTargetX = (gameWidth - subScreenWidth) << 8;
+	
+		if (subScTargetY < 0) subScTargetY = 0;
+		if (subScTargetY > (gameHeight - subScreenHeight) << 8) subScTargetY = (gameHeight - subScreenHeight) << 8;
+	}
+
+	subScX += (subScTargetX - subScX) >> 2;
+	subScY += (subScTargetY - subScY) >> 2;
+	
+	if (displayModeIs8Bit) {
+	
+		if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) {
+			
+			int offsX = 0, offsY = 0;
+
+
+			if (getKeysHeld() & KEY_LEFT) {
+				offsX -= 1;
+			}
+			
+			if (getKeysHeld() & KEY_RIGHT) {
+				offsX += 1;
+			}
+	
+			if (getKeysHeld() & KEY_UP) {
+				offsY -= 1;
+			}
+	
+			if (getKeysHeld() & KEY_DOWN) {
+				offsY += 1;
+			}
+			
+			if (((gameScreenSwap) && (getKeysHeld() & KEY_L)) || ((!gameScreenSwap) && (getKeysHeld() & KEY_R))) {
+				subScTargetX += offsX << 8;
+				subScTargetY += offsY << 8;
+			} else {
+				scX += offsX;
+				scY += offsY;
+			}
+		}
+
+		if (!scaledMode) {
+			
+			if (scX + 256 > gameWidth - 1) {
+				scX = gameWidth - 1 - 256;
+			}
+	
+			if (scX < 0) {
+				scX = 0;
+			}
+	
+			if (scY + 192 > gameHeight - 1) {
+				scY = gameHeight - 1 - 192;
+			}
+	
+			if (scY < 0) {
+				scY = 0;
+			}
+			
+			setZoomedScreenScroll(subScX, subScY);
+			setZoomedScreenScale(subScreenWidth, (subScreenHeight * 256) / 192);
+	
+		
+			setMainScreenScroll(scX << 8, (scY << 8) + (shakePos << 8));
+			setMainScreenScale(256, 256);		// 1:1 scale
+	
+		} else {
+		
+			if (scY > gameHeight - 192 - 1) {
+				scY = gameHeight - 192 - 1;
+			}
+
+			if (scY < 0) {
+				scY = 0;
+			}
+		
+			setZoomedScreenScroll(subScX, subScY);
+			setZoomedScreenScale(subScreenWidth, (subScreenHeight * 256) / 192);
+	
+			setMainScreenScroll(64, (scY << 8) + (shakePos << 8));
+			setMainScreenScale(320, 256);		// 1:1 scale
+			
+		}
+	} else {
+		setZoomedScreenScroll(0, 0);
+		setZoomedScreenScale(320, 256);
+
+		setMainScreenScroll(0, 0);
+		setMainScreenScale(320, 256);		// 1:1 scale
+	}
+	
+	// Enable on screen keyboard when pen taps icon
+	if ((keyboardIcon) && (penX < 32) && (penY > 160) && (penHeld)) {
+		setKeyboardEnable(true);
+	}
+	
+	if (keyboardEnable) {
+		if (DS::getKeyboardClosed()) {
+			setKeyboardEnable(false);
+		}
+	}
+
+	updateOAM();
+
+	//PALETTE[0] = RGB15(0, 0, 0);
+	REG_IF = IRQ_VBLANK;
+}
+
+int getMillis() {
+	return currentTimeMillis;
+//	return frameCount * FRAME_TIME;
+}
+
+void setTimerCallback(OSystem::TimerProc proc, int interval) {
+//	consolePrintf("Set timer proc %x, int %d\n", proc, interval);
+	callback = proc;
+	callbackInterval = interval;
+	callbackTimer = interval;
+}
+
+void timerTickHandler() {
+	REG_IF = IRQ_TIMER0;
+	if ((callback) && (callbackTimer > 0)) {
+		callbackTimer--;
+	}
+	currentTimeMillis++;
+}
+
+void setTalkPos(int x, int y) {
+//	if (gameID != Scumm::GID_SAMNMAX) {
+//		setTopScreenTarget(x, 0);
+//	} else {
+		setTopScreenTarget(x, y);
+//	}
+}
+
+void setTopScreenTarget(int x, int y) {
+	subScTargetX = (x - (subScreenWidth >> 1));
+	subScTargetY = (y - (subScreenHeight >> 1));
+
+	if (subScTargetX < 0) subScTargetX = 0;
+	if (subScTargetX > gameWidth - subScreenWidth) subScTargetX = gameWidth - subScreenWidth;
+
+	if (subScTargetY < 0) subScTargetY = 0;
+	if (subScTargetY > gameHeight - subScreenHeight) subScTargetY = gameHeight - subScreenHeight;
+	
+	subScTargetX <<=8;
+	subScTargetY <<=8;
+}
+
+void initHardware() {
+	// Guard band
+//((int *) (0x023FFF00)) = 0xBEEFCAFE;
+
+
+	penInit();
+
+	powerON(POWER_ALL);
+/*	vramSetBankA(VRAM_A_MAIN_BG); 
+	vramSetBankB(VRAM_B_MAIN_BG); 
+	vramSetBankC(VRAM_C_SUB_BG); */
+	vramSetBankI(VRAM_I_SUB_SPRITE); 
+	vramSetBankG(VRAM_G_MAIN_SPRITE); 
+	
+	currentTimeMillis = 0;
+
+
+/*
+	// Set up a millisecond counter
+	TIMER0_CR = 0;
+	TIMER0_DATA = 0xFFFF;
+	TIMER0_CR = TIMER_ENABLE | TIMER_CASCADE;
+*/
+
+
+
+	PALETTE[255] = RGB15(0,31,0);
+
+	// Allocate save buffer for game screen
+//	savedBuffer = new u8[320 * 200];
+	displayMode16Bit();
+	
+	memset(BG_GFX, 0, 512 * 256 * 2);	
+	scaledMode = true;
+	scX = 0;
+	scY = 0;
+	subScX = 0;
+	subScY = 0;
+	subScTargetX = 0;
+	subScTargetY = 0;
+	
+	//lcdSwap();
+	POWER_CR &= ~POWER_SWAP_LCDS;
+	
+	frameCount = 0;
+	callback = NULL;
+	
+//	vramSetBankH(VRAM_H_SUB_BG); 
+	
+
+//	// Do text stuff
+	//BG0_CR = BG_MAP_BASE(0) | BG_TILE_BASE(1);
+//	BG0_Y0 = 48;
+	
+	PALETTE[255] = RGB15(31,31,31);//by default font will be rendered with color 255
+	
+	//consoleInit() is a lot more flexible but this gets you up and running quick
+//	consoleInitDefault((u16*)SCREEN_BASE_BLOCK(0), (u16*)CHAR_BASE_BLOCK(1), 16);
+	//consolePrintSet(0, 6);
+	
+	//irqs are nice
+	irqInit();
+//	irqInitHandler();
+	irqSet(IRQ_VBLANK, VBlankHandler);
+	irqSet(IRQ_TIMER0, timerTickHandler);
+	irqSet(IRQ_TIMER2, soundBufferEmptyHandler);
+	
+	irqEnable(IRQ_VBLANK);
+	irqEnable(IRQ_TIMER0);
+	irqEnable(IRQ_TIMER2);
+	
+	
+	// Set up a millisecond timer
+	TIMER0_CR = 0;
+	TIMER0_DATA = (u32) TIMER_FREQ(1000);
+	TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1 | TIMER_IRQ_REQ;	
+	REG_IME = 1;
+
+	PALETTE[255] = RGB15(0,0,31);
+
+	initSprites();
+	
+//	videoSetModeSub(MODE_3_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
+	
+	// Convert texture from 24bit 888 to 16bit 1555, remembering to set top bit!
+	u8* srcTex = (u8 *) icons_raw;
+	for (int r = 32 * 160 ; r >= 0; r--) {
+		SPRITE_GFX_SUB[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
+		SPRITE_GFX[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
+	}
+
+	WAIT_CR &= ~(0x0080);
+	REG_WRAM_CNT = 0;
+
+}
+
+
+void setKeyboardIcon(bool enable) {
+	keyboardIcon = enable;
+}
+
+bool getKeyboardIcon() {
+	return keyboardIcon;
+}
+
+
+////////////////////
+// Pen stuff
+////////////////////
+
+
+void penInit() {
+	penDown = false;
+	penHeld = false;
+	penReleased = false;
+	penDownLastFrame = false;
+	penDownSaved = false;
+	penReleasedSaved = false;
+	penDownFrames = 0;
+	consumeKeys();
+}
+
+void penUpdate() {
+
+//	if (getKeysHeld() & KEY_L) consolePrintf("%d, %d   penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1);
+
+	if ((penDownFrames > 1)) {			// Is this right?  Dunno, but it works for me.
+
+		if ((penHeld)) {
+			penHeld = true;
+			penDown = false;
+
+			if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
+				penX = IPC->touchXpx + touchXOffset;
+				penY = IPC->touchYpx + touchYOffset;
+			}
+
+		} else {
+			penDown = true;
+			penHeld = true;
+			penDownSaved = true;
+
+			//if ( (ABS(penX - IPC->touchXpx) < 10) && (ABS(penY - IPC->touchYpx) < 10) ) {
+			if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
+				penX = IPC->touchXpx;
+				penY = IPC->touchYpx;
+			}
+			//}
+		}
+
+	} else {
+		if (penHeld) {
+			penReleased = true;
+			penReleasedSaved = true;
+		} else {
+			penReleased = false;
+		}
+
+		penDown = false;
+		penHeld = false;
+	}
+
+
+	if ((IPC->touchZ1 > 0) || ((penDownFrames == 2)) ) {
+		penDownLastFrame = true;
+		penDownFrames++;
+	} else {
+		penDownLastFrame = false;
+		penDownFrames = 0;
+	}
+	
+}
+
+int leftHandedSwap(int keys) {
+	// Start and select are unchanged
+	if (leftHandedMode) {
+		int result = keys & (~(KEY_R | KEY_L | KEY_Y | KEY_A | KEY_B | KEY_X | KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN));
+		
+		if (keys & KEY_L) result |= KEY_R;
+		if (keys & KEY_R) result |= KEY_L;
+	
+		if (keys & KEY_LEFT) result |= KEY_Y;
+		if (keys & KEY_RIGHT) result |= KEY_A;
+		if (keys & KEY_DOWN) result |= KEY_B;
+		if (keys & KEY_UP) result |= KEY_X;
+	
+		if (keys & KEY_Y) result |= KEY_LEFT;
+		if (keys & KEY_A) result |= KEY_RIGHT;
+		if (keys & KEY_B) result |= KEY_DOWN;
+		if (keys & KEY_X) result |= KEY_UP;
+	
+		return result;
+	} else {
+		return keys;
+	}
+}
+
+void keysUpdate() {
+	scanKeys();
+	keysDownSaved |= leftHandedSwap(keysDown());
+	keysReleasedSaved |= leftHandedSwap(keysUp());
+}
+
+int getKeysDown() {
+	return keysDownSaved;
+}
+
+int getKeysHeld() {
+	return leftHandedSwap(keysHeld());
+}
+
+int getKeysReleased() {
+	return keysReleasedSaved;
+}
+
+void consumeKeys() {
+	keysDownSaved = 0;
+	keysReleasedSaved = 0;
+}
+
+bool getPenDown() {
+	return penDownSaved;
+}
+
+bool getPenHeld() {
+	return penHeld;
+}
+
+bool getPenReleased() {
+	return penReleasedSaved;
+}
+
+void consumePenEvents() {
+	penDownSaved = false;
+	penReleasedSaved = false;
+}
+
+int getPenX() {
+	int x = ((penX * touchScX) >> 8) + touchX;
+	x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x);
+	return x;
+}
+
+int getPenY() {
+	int y = ((penY * touchScY) >> 8) + touchY;
+	y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y);
+	return y;
+}
+
+GLvector getPenPos() {
+	GLvector v;
+	
+	v.x = (penX * inttof32(1)) / SCREEN_WIDTH;
+	v.y = (penY * inttof32(1)) / SCREEN_HEIGHT;
+	
+	return v;
+}
+
+void formatSramOption() {
+	consolePrintf("The following files are present in save RAM:\n");
+	DSSaveFileManager::instance()->listFiles();
+	
+	consolePrintf("\nAre you sure you want to\n");
+	consolePrintf("DELETE all files?\n");
+	consolePrintf("A = Yes, X = No\n");
+	
+	while (true) {
+		if (keysHeld() & KEY_A) {
+			DSSaveFileManager::instance()->formatSram();
+			consolePrintf("SRAM cleared!\n");
+			return;
+		}
+	
+		if (keysHeld() & KEY_X) {
+			consolePrintf("Whew, that was close!\n");
+			return;
+		}
+	}
+}
+
+
+void setIndyFightState(bool st) {
+	indyFightState = st;
+	indyFightRight = true;
+}
+
+bool getIndyFightState() {
+	return indyFightState;
+}
+
+/////////////////
+// GBAMP
+/////////////////
+
+bool GBAMPAvail = false;
+
+void initGBAMP() {	
+	FAT_InitFiles();
+	if (disc_IsInserted()) {
+		GBAMPAvail = true;
+		consolePrintf("Found flash card reader!\n");
+	} else {
+		GBAMPAvail = false;
+		consolePrintf("Flash card reader not found!\n");
+	}
+}
+	 
+bool isGBAMPAvailable() {
+	return GBAMPAvail;
+}
+
+
+
+/////////////////
+// Main
+/////////////////
+
+static const Common::String test("poo", 1, 16);
+
+
+
+int main(void)
+{
+	soundCallback = NULL;
+	
+
+	initHardware();
+	
+	// Let arm9 read cartridge
+	*((u16 *) (0x04000204)) &= ~0x0080;
+	
+	lastCallbackFrame = 0;
+	tweak = 0;
+	
+	indyFightState = false;
+	indyFightRight = true;
+
+	// CPU speed = 67108864
+	// 8 frames = 2946   368.5 bytes per fr
+
+//	playSound(stretch, 47619, false);
+//	playSound(twang, 11010, true);   // 18640
+
+//	bufferSize = 10;
+	bufferRate = 22050;
+	bufferFrame = 0;
+//	bufferSamples = (bufferRate * bufferSize) / 60;
+	bufferSamples = 4096;
+	
+	bufferFirstHalf = false;
+	bufferSecondHalf = true;
+	
+	lastEventFrame = 0;
+	mouseMode = MOUSE_LEFT;
+
+	
+
+	
+	int bytes = (2 * (bufferSamples)) + 100;
+	
+	soundBuffer = (s16 *) malloc(bytes * 2);
+
+
+	soundHiPart = true;
+/*
+	TIMER1_CR = 0;
+	TIMER1_DATA = TIMER_FREQ(bufferRate);
+	TIMER1_CR = TIMER_ENABLE | TIMER_DIV_1;
+	
+	TIMER2_CR = 0;
+	TIMER2_DATA = 0xFFFF - (bufferSamples / 2);
+	TIMER2_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
+	*/
+	// 2945 - 2947
+	
+
+	
+//	for (int r = 2946; r < 3000; r++) {
+//		soundBuffer[r] = 30000;
+//	}
+	
+
+	
+	consolePrintf("------------------------\n");
+	consolePrintf("ScummVM DS\n");
+	consolePrintf("Ported by Neil Millstone\n");
+#ifdef DS_SCUMM_BUILD
+	consolePrintf("Version 0.61 build A\n");
+#else
+	consolePrintf("Version 0.61 build B\n");
+#endif
+	consolePrintf("------------------------\n");
+	consolePrintf("L/R + D-pad/pen: Scroll view\n");
+	consolePrintf("D-pad left:  Left mouse button\n");
+	consolePrintf("D-pad right: Right mouse button\n");
+	consolePrintf("D-pad up:    Hover mouse\n");
+	consolePrintf("D-pad down:  Skip dialog line\n");
+	consolePrintf("B button:    Skip cutscenes\n");
+	consolePrintf("Select:		DS Options menu\n");
+	consolePrintf("Start:       Game menu\n");
+	consolePrintf("Y (in game): Toggle console\n");
+	consolePrintf("X:           Toggle keyboard\n");
+	consolePrintf("A:			Swap screens\n");
+	consolePrintf("L + R on bootup: Clear SRAM\n\n");
+	consolePrintf("For a complete poo list see the\n");
+	consolePrintf("help screen.\npoo\n");
+
+
+	for (int r = 0; r < bytes; r++) {
+		soundBuffer[r] = 0;
+	}
+	
+	consolePrintf("length=%d str='%s'\n", test.size(), test.c_str());
+
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	playSound(soundBuffer, (bufferSamples * 2), true);
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	swiWaitForVBlank();
+	
+
+
+	// Create a file system node to force search for a zip file in GBA rom space
+	DSFileSystemNode* node = new DSFileSystemNode();
+	if (!node->getZip() || (!node->getZip()->isReady())) {
+		// If not found, init CF/SD driver
+		initGBAMP();
+	}
+	delete node;
+
+	
+
+	updateStatus();
+	
+	
+//	OSystem_DS::instance();
+	g_system = new OSystem_DS();
+	assert(g_system);
+
+	if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
+		formatSramOption();
+	}
+
+//	printf("'%s'", Common::ConfigManager::kTransientDomain.c_str());
+	//printf("'%s'", Common::ConfigManager::kApplicationDomain.c_str());
+	
+
+	char* argv[2] = {"/scummvmds", "--config=scummvmb.ini"};
+#ifdef DS_NON_SCUMM_BUILD	
+
+	while (1) {
+		scummvm_main(2, (char **) &argv);
+	}
+#else
+	while (1) {
+		scummvm_main(1, (char **) &argv);
+	}
+#endif
+	
+
+	return 0;
+}
+
+}
+
+int main() {
+	DS::main();
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/dsmain.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/dsmain.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/dsmain.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/dsmain.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,236 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DSMAIN_H
+#define _DSMAIN_H
+
+#include <nds.h>
+#include "stdafx.h"
+#include "system.h"
+#include "scummconsole.h"
+#include "nds/scummvm_ipc.h"
+
+namespace DS {
+
+// Pen reading functions
+void 	penInit();
+void 	penUpdate();
+bool 	getPenDown();
+bool 	getPenHeld();
+bool 	getPenReleased();
+int 	getPenX();
+int 	getPenY();
+GLvector getPenPos();
+void 	consumePenEvents();
+
+// Pad reading
+int 	getKeysHeld();
+void 	keysUpdate();
+int 	getKeysDown();
+int 	getKeysReleased();
+void 	consumeKeys();
+int 	leftHandedSwap(int keys);
+
+// Video
+void 	displayMode8Bit();											// Switch to 8-bit mode5
+void 	displayMode16Bit();										// Switch to 16-bit mode5
+
+// Flip double buffer
+void 	displayMode16BitFlipBuffer();
+
+// Get address of current back buffer
+u16* 	get16BitBackBuffer();
+u16* 	get8BitBackBuffer();
+
+void 	setTalkPos(int x, int y);
+void 	setTopScreenTarget(int x, int y);
+
+// Timers
+void 	setTimerCallback(OSystem::TimerProc proc, int interval);		// Setup a callback function at a regular interval
+int 	getMillis();													// Return the current runtime in milliseconds
+void 	doTimerCallback();												// Call callback function if required
+
+// Sound
+void 	setSoundProc(OSystem::SoundProc proc, void* param);			// Setup a callback function for sound
+void 	doSoundCallback();												// Call function if sound buffers need more data
+void 	playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050);		// Start a sound
+void 	stopSound(int channel);
+
+// Event queue
+void 	addEventsToQueue();
+void 	VBlankHandler();
+
+// Sam and Max Stuff
+void 	setGameID(int id);
+void 	setCursorIcon(const u8* icon, uint w, uint h, byte keycolor);
+
+// Shake
+void 	setShakePos(int shakePos);
+
+// Reports
+void 	memoryReport();
+
+// GBAMP
+bool 	isGBAMPAvailable();
+
+// Sleep (I'd like some of that right now)
+void 	checkSleepMode();
+
+// Virtual keyboard
+void 	setKeyboardIcon(bool enable);
+bool 	getKeyboardIcon();
+void 	setKeyboardEnable(bool en);
+bool 	getKeyboardEnable();
+
+// Options
+void 	setLeftHanded(bool enable);
+void 	setTouchXOffset(int x);
+void 	setTouchYOffset(int y);
+void 	setUnscaledMode(bool enable);
+void 	setIndyFightState(bool st);
+bool 	getIndyFightState();
+
+// Display
+bool 	getIsDisplayMode8Bit();
+void 	setGameSize(int width, int height);
+int		getGameWidth();
+int		getGameHeight();
+
+}
+
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DSMAIN_H
+#define _DSMAIN_H
+
+#include <nds.h>
+#include "stdafx.h"
+#include "system.h"
+#include "scummconsole.h"
+#include "nds/scummvm_ipc.h"
+
+namespace DS {
+
+// Pen reading functions
+void 	penInit();
+void 	penUpdate();
+bool 	getPenDown();
+bool 	getPenHeld();
+bool 	getPenReleased();
+int 	getPenX();
+int 	getPenY();
+GLvector getPenPos();
+void 	consumePenEvents();
+
+// Pad reading
+int 	getKeysHeld();
+void 	keysUpdate();
+int 	getKeysDown();
+int 	getKeysReleased();
+void 	consumeKeys();
+int 	leftHandedSwap(int keys);
+
+// Video
+void 	displayMode8Bit();											// Switch to 8-bit mode5
+void 	displayMode16Bit();										// Switch to 16-bit mode5
+
+// Flip double buffer
+void 	displayMode16BitFlipBuffer();
+
+// Get address of current back buffer
+u16* 	get16BitBackBuffer();
+u16* 	get8BitBackBuffer();
+
+void 	setTalkPos(int x, int y);
+void 	setTopScreenTarget(int x, int y);
+
+// Timers
+void 	setTimerCallback(OSystem::TimerProc proc, int interval);		// Setup a callback function at a regular interval
+int 	getMillis();													// Return the current runtime in milliseconds
+void 	doTimerCallback();												// Call callback function if required
+
+// Sound
+void 	setSoundProc(OSystem::SoundProc proc, void* param);			// Setup a callback function for sound
+void 	doSoundCallback();												// Call function if sound buffers need more data
+void 	playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050);		// Start a sound
+void 	stopSound(int channel);
+
+// Event queue
+void 	addEventsToQueue();
+void 	VBlankHandler();
+
+// Sam and Max Stuff
+void 	setGameID(int id);
+void 	setCursorIcon(const u8* icon, uint w, uint h, byte keycolor);
+
+// Shake
+void 	setShakePos(int shakePos);
+
+// Reports
+void 	memoryReport();
+
+// GBAMP
+bool 	isGBAMPAvailable();
+
+// Sleep (I'd like some of that right now)
+void 	checkSleepMode();
+
+// Virtual keyboard
+void 	setKeyboardIcon(bool enable);
+bool 	getKeyboardIcon();
+void 	setKeyboardEnable(bool en);
+bool 	getKeyboardEnable();
+
+// Options
+void 	setLeftHanded(bool enable);
+void 	setTouchXOffset(int x);
+void 	setTouchYOffset(int y);
+void 	setUnscaledMode(bool enable);
+void 	setIndyFightState(bool st);
+bool 	getIndyFightState();
+
+// Display
+bool 	getIsDisplayMode8Bit();
+void 	setGameSize(int width, int height);
+int		getGameWidth();
+int		getGameHeight();
+
+}
+
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/dsmain.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,412 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "dsoptions.h"
+#include "dsmain.h"
+#include "gui/dialog.h"
+#include "gui/newgui.h"
+#include "gui/listwidget.h"
+#include "osystem_ds.h"
+#include "engines/scumm/scumm.h"
+#include "touchkeyboard.h"
+
+#ifdef DS_SCUMM_BUILD
+namespace Scumm {
+	extern Common::StringList generateSavegameList(Scumm::ScummEngine *scumm, bool saveMode);
+	extern Scumm::ScummEngine *g_scumm;
+}
+#endif
+
+namespace DS {
+
+DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) {
+	addButton(this, 10, 140, "Close", GUI::kCloseCmd, 'C');
+	
+#ifdef DS_SCUMM_BUILD
+	if (!DS::isGBAMPAvailable()) {
+//		addButton(this, 100, 140, "Delete Save", 'dels', 'D');
+	}
+#endif
+
+	new GUI::StaticTextWidget(this, 0, 10, 280, 20, "ScummVM DS Options", GUI::kTextAlignCenter);
+
+	_leftHandedCheckbox = new GUI::CheckboxWidget(this, 20, 30, 280, 20, "Left handed mode", 0, 'L');
+	_indyFightCheckbox = new GUI::CheckboxWidget(this, 20, 50, 280, 20, "Indy fighting controls", 0, 'I');
+	_unscaledCheckbox = new GUI::CheckboxWidget(this, 20, 70, 280, 20, "Unscaled lower screen", 0, 'S');
+
+	new GUI::StaticTextWidget(this, 20, 90, 110, 20, "Touch X Offset", GUI::kTextAlignLeft);
+	_touchX = new GUI::SliderWidget(this, 130, 90, 130, 12, 1);
+	_touchX->setMinValue(-8);
+	_touchX->setMaxValue(+8);
+	_touchX->setValue(0);
+	_touchX->setFlags(GUI::WIDGET_CLEARBG);
+
+	new GUI::StaticTextWidget(this, 20, 110, 110, 20, "Touch Y Offset", GUI::kTextAlignLeft);
+	_touchY = new GUI::SliderWidget(this, 130, 110, 130, 12, 2);
+	_touchY->setMinValue(-8);
+	_touchY->setMaxValue(+8);
+	_touchY->setValue(0);
+	_touchY->setFlags(GUI::WIDGET_CLEARBG);
+
+	new GUI::StaticTextWidget(this, 130 + 65 - 10, 130, 20, 20, "0", GUI::kTextAlignCenter);
+	new GUI::StaticTextWidget(this, 130 + 130 - 10, 130, 20, 20, "8", GUI::kTextAlignCenter);
+	new GUI::StaticTextWidget(this, 130 - 10, 130, 20, 20, "-8", GUI::kTextAlignCenter);
+
+#ifdef DS_SCUMM_BUILD
+	_delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm);
+#endif
+
+	if (ConfMan.hasKey("lefthanded", "ds")) {
+		_leftHandedCheckbox->setState(ConfMan.getBool("lefthanded", "ds"));
+	} else {
+		_leftHandedCheckbox->setState(false);
+	}
+
+	if (ConfMan.hasKey("unscaled", "ds")) {
+		_unscaledCheckbox->setState(ConfMan.getBool("unscaled", "ds"));
+	} else {
+		_unscaledCheckbox->setState(false);
+	}
+	
+	_indyFightCheckbox->setState(DS::getIndyFightState());
+
+	if (ConfMan.hasKey("xoffset", "ds")) {
+		_touchX->setValue(ConfMan.getInt("xoffset", "ds"));
+	} else {
+		_touchX->setValue(0);
+	}
+
+	if (ConfMan.hasKey("yoffset", "ds")) {
+		_touchY->setValue(ConfMan.getInt("yoffset", "ds"));
+	} else {
+		_touchY->setValue(0);
+	}
+	
+}
+
+DSOptionsDialog::~DSOptionsDialog() {
+	ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds");
+	ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds");
+	ConfMan.setInt("xoffset", _touchX->getValue(), "ds");
+	ConfMan.setInt("yoffset", _touchY->getValue(), "ds");
+	DS::setOptions();
+	DS::setIndyFightState(_indyFightCheckbox->getState());
+	ConfMan.flushToDisk();
+}
+
+
+void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+	if (cmd == GUI::kCloseCmd) {
+		close();
+	}
+
+#ifdef DS_SCUMM_BUILD
+/*	if (cmd == 'dels') {
+		_delDialog->setList(Scumm::generateSavegameList(Scumm::g_scumm, false));
+		_delDialog->handleCommand(NULL, GUI::kListSelectionChangedCmd, 0);
+		
+		OSystem::Event event;
+		event.type = OSystem::EVENT_KEYDOWN;
+		event.kbd.ascii = SDLK_DOWN;
+		event.kbd.keycode = SDLK_DOWN;
+		OSystem_DS::instance()->addEvent(event);
+
+		event.type = OSystem::EVENT_KEYUP;
+		OSystem_DS::instance()->addEvent(event);
+				
+		int idx = _delDialog->runModal();
+		
+		if (idx >= 0) {
+			char name[256];
+			Scumm::g_scumm->makeSavegameName(name, idx, false);
+			if (!DS::isGBAMPAvailable()) {
+				((DSSaveFileManager *) (OSystem_DS::instance()->getSavefileManager()))->deleteFile(name);
+			}
+		}
+		
+	}*/
+#endif
+	
+
+}
+
+void showOptionsDialog() {
+	OSystem_DS* system = OSystem_DS::instance();
+
+	OSystem::Event event;
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.keycode = 'P';		// F5
+	event.kbd.ascii = 'P';
+	event.kbd.flags = 0;
+	system->addEvent(event);
+
+	DS::displayMode16Bit();
+	
+
+	DSOptionsDialog* d = new DSOptionsDialog();
+	d->runModal();
+	delete d;
+	
+	
+	DS::displayMode8Bit();
+
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.keycode = 'P';		// F5
+	event.kbd.ascii = 'P';
+	event.kbd.flags = 0;
+	system->addEvent(event);
+}
+
+void setOptions() {
+	ConfMan.addGameDomain("ds");
+
+	if (ConfMan.hasKey("lefthanded", "ds")) {
+		DS::setLeftHanded(ConfMan.getBool("lefthanded", "ds"));
+	} else {
+		DS::setLeftHanded(false);
+	}
+
+	if (ConfMan.hasKey("unscaled", "ds")) {
+		DS::setUnscaledMode(ConfMan.getBool("unscaled", "ds"));
+	} else {
+		DS::setUnscaledMode(false);
+	}
+
+	if (ConfMan.hasKey("xoffset", "ds")) {
+		DS::setTouchXOffset(ConfMan.getInt("xoffset", "ds"));
+	} else {
+		DS::setTouchXOffset(0);
+	}
+
+	if (ConfMan.hasKey("yoffset", "ds")) {
+		DS::setTouchYOffset(ConfMan.getInt("yoffset", "ds"));
+	} else {
+		DS::setTouchXOffset(0);
+	}
+	
+}
+
+}
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#include "dsoptions.h"
+#include "dsmain.h"
+#include "gui/dialog.h"
+#include "gui/newgui.h"
+#include "gui/listwidget.h"
+#include "osystem_ds.h"
+#include "engines/scumm/scumm.h"
+#include "touchkeyboard.h"
+
+#ifdef DS_SCUMM_BUILD
+namespace Scumm {
+	extern Common::StringList generateSavegameList(Scumm::ScummEngine *scumm, bool saveMode);
+	extern Scumm::ScummEngine *g_scumm;
+}
+#endif
+
+namespace DS {
+
+DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) {
+	addButton(this, 10, 140, "Close", GUI::kCloseCmd, 'C');
+	
+#ifdef DS_SCUMM_BUILD
+	if (!DS::isGBAMPAvailable()) {
+//		addButton(this, 100, 140, "Delete Save", 'dels', 'D');
+	}
+#endif
+
+	new GUI::StaticTextWidget(this, 0, 10, 280, 20, "ScummVM DS Options", GUI::kTextAlignCenter);
+
+	_leftHandedCheckbox = new GUI::CheckboxWidget(this, 20, 30, 280, 20, "Left handed mode", 0, 'L');
+	_indyFightCheckbox = new GUI::CheckboxWidget(this, 20, 50, 280, 20, "Indy fighting controls", 0, 'I');
+	_unscaledCheckbox = new GUI::CheckboxWidget(this, 20, 70, 280, 20, "Unscaled lower screen", 0, 'S');
+
+	new GUI::StaticTextWidget(this, 20, 90, 110, 20, "Touch X Offset", GUI::kTextAlignLeft);
+	_touchX = new GUI::SliderWidget(this, 130, 90, 130, 12, 1);
+	_touchX->setMinValue(-8);
+	_touchX->setMaxValue(+8);
+	_touchX->setValue(0);
+	_touchX->setFlags(GUI::WIDGET_CLEARBG);
+
+	new GUI::StaticTextWidget(this, 20, 110, 110, 20, "Touch Y Offset", GUI::kTextAlignLeft);
+	_touchY = new GUI::SliderWidget(this, 130, 110, 130, 12, 2);
+	_touchY->setMinValue(-8);
+	_touchY->setMaxValue(+8);
+	_touchY->setValue(0);
+	_touchY->setFlags(GUI::WIDGET_CLEARBG);
+
+	new GUI::StaticTextWidget(this, 130 + 65 - 10, 130, 20, 20, "0", GUI::kTextAlignCenter);
+	new GUI::StaticTextWidget(this, 130 + 130 - 10, 130, 20, 20, "8", GUI::kTextAlignCenter);
+	new GUI::StaticTextWidget(this, 130 - 10, 130, 20, 20, "-8", GUI::kTextAlignCenter);
+
+#ifdef DS_SCUMM_BUILD
+	_delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm);
+#endif
+
+	if (ConfMan.hasKey("lefthanded", "ds")) {
+		_leftHandedCheckbox->setState(ConfMan.getBool("lefthanded", "ds"));
+	} else {
+		_leftHandedCheckbox->setState(false);
+	}
+
+	if (ConfMan.hasKey("unscaled", "ds")) {
+		_unscaledCheckbox->setState(ConfMan.getBool("unscaled", "ds"));
+	} else {
+		_unscaledCheckbox->setState(false);
+	}
+	
+	_indyFightCheckbox->setState(DS::getIndyFightState());
+
+	if (ConfMan.hasKey("xoffset", "ds")) {
+		_touchX->setValue(ConfMan.getInt("xoffset", "ds"));
+	} else {
+		_touchX->setValue(0);
+	}
+
+	if (ConfMan.hasKey("yoffset", "ds")) {
+		_touchY->setValue(ConfMan.getInt("yoffset", "ds"));
+	} else {
+		_touchY->setValue(0);
+	}
+	
+}
+
+DSOptionsDialog::~DSOptionsDialog() {
+	ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds");
+	ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds");
+	ConfMan.setInt("xoffset", _touchX->getValue(), "ds");
+	ConfMan.setInt("yoffset", _touchY->getValue(), "ds");
+	DS::setOptions();
+	DS::setIndyFightState(_indyFightCheckbox->getState());
+	ConfMan.flushToDisk();
+}
+
+
+void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+	if (cmd == GUI::kCloseCmd) {
+		close();
+	}
+
+#ifdef DS_SCUMM_BUILD
+/*	if (cmd == 'dels') {
+		_delDialog->setList(Scumm::generateSavegameList(Scumm::g_scumm, false));
+		_delDialog->handleCommand(NULL, GUI::kListSelectionChangedCmd, 0);
+		
+		OSystem::Event event;
+		event.type = OSystem::EVENT_KEYDOWN;
+		event.kbd.ascii = SDLK_DOWN;
+		event.kbd.keycode = SDLK_DOWN;
+		OSystem_DS::instance()->addEvent(event);
+
+		event.type = OSystem::EVENT_KEYUP;
+		OSystem_DS::instance()->addEvent(event);
+				
+		int idx = _delDialog->runModal();
+		
+		if (idx >= 0) {
+			char name[256];
+			Scumm::g_scumm->makeSavegameName(name, idx, false);
+			if (!DS::isGBAMPAvailable()) {
+				((DSSaveFileManager *) (OSystem_DS::instance()->getSavefileManager()))->deleteFile(name);
+			}
+		}
+		
+	}*/
+#endif
+	
+
+}
+
+void showOptionsDialog() {
+	OSystem_DS* system = OSystem_DS::instance();
+
+	OSystem::Event event;
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.keycode = 'P';		// F5
+	event.kbd.ascii = 'P';
+	event.kbd.flags = 0;
+	system->addEvent(event);
+
+	DS::displayMode16Bit();
+	
+
+	DSOptionsDialog* d = new DSOptionsDialog();
+	d->runModal();
+	delete d;
+	
+	
+	DS::displayMode8Bit();
+
+	event.type = OSystem::EVENT_KEYDOWN;
+	event.kbd.keycode = 'P';		// F5
+	event.kbd.ascii = 'P';
+	event.kbd.flags = 0;
+	system->addEvent(event);
+}
+
+void setOptions() {
+	ConfMan.addGameDomain("ds");
+
+	if (ConfMan.hasKey("lefthanded", "ds")) {
+		DS::setLeftHanded(ConfMan.getBool("lefthanded", "ds"));
+	} else {
+		DS::setLeftHanded(false);
+	}
+
+	if (ConfMan.hasKey("unscaled", "ds")) {
+		DS::setUnscaledMode(ConfMan.getBool("unscaled", "ds"));
+	} else {
+		DS::setUnscaledMode(false);
+	}
+
+	if (ConfMan.hasKey("xoffset", "ds")) {
+		DS::setTouchXOffset(ConfMan.getInt("xoffset", "ds"));
+	} else {
+		DS::setTouchXOffset(0);
+	}
+
+	if (ConfMan.hasKey("yoffset", "ds")) {
+		DS::setTouchYOffset(ConfMan.getInt("yoffset", "ds"));
+	} else {
+		DS::setTouchXOffset(0);
+	}
+	
+}
+
+}
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,122 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DSOPTIONS_H_
+#define _DSOPTIONS_H_
+
+#include "stdafx.h"
+
+#include "common/scummsys.h"
+#include "common/str.h"
+
+#include "gui/object.h"
+#include "gui/widget.h"
+#include "gui/dialog.h"
+#include "scumm/dialogs.h"
+
+namespace DS {
+
+class DSOptionsDialog : public GUI::Dialog {
+
+public:
+	DSOptionsDialog();
+	~DSOptionsDialog();
+	
+protected:
+	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+
+
+	GUI::SliderWidget* _touchX;
+	GUI::SliderWidget* _touchY;
+	GUI::CheckboxWidget* _leftHandedCheckbox;
+	GUI::CheckboxWidget* _unscaledCheckbox;
+	GUI::CheckboxWidget* _indyFightCheckbox;
+#ifdef DS_SCUMM_BUILD
+	Scumm::SaveLoadChooser* _delDialog;
+#endif
+
+};
+
+extern void showOptionsDialog();
+extern void setOptions();
+
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _DSOPTIONS_H_
+#define _DSOPTIONS_H_
+
+#include "stdafx.h"
+
+#include "common/scummsys.h"
+#include "common/str.h"
+
+#include "gui/object.h"
+#include "gui/widget.h"
+#include "gui/dialog.h"
+#include "scumm/dialogs.h"
+
+namespace DS {
+
+class DSOptionsDialog : public GUI::Dialog {
+
+public:
+	DSOptionsDialog();
+	~DSOptionsDialog();
+	
+protected:
+	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+
+
+	GUI::SliderWidget* _touchX;
+	GUI::SliderWidget* _touchY;
+	GUI::CheckboxWidget* _leftHandedCheckbox;
+	GUI::CheckboxWidget* _unscaledCheckbox;
+	GUI::CheckboxWidget* _indyFightCheckbox;
+#ifdef DS_SCUMM_BUILD
+	Scumm::SaveLoadChooser* _delDialog;
+#endif
+
+};
+
+extern void showOptionsDialog();
+extern void setOptions();
+
+}
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/dsoptions.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,844 @@
+/*
+
+	disc_io.c
+
+	uniformed io-interface to work with Chishm's FAT library
+
+	Written by MightyMax
+  
+	Modified by Chishm:
+	2005-11-06
+		* Added WAIT_CR modifications for NDS
+
+	Modified by www.neoflash.com:
+	2006-02-03
+		* Added SUPPORT_* defines, comment out any of the SUPPORT_* defines in disc_io.h to remove support
+		  for the given interface and stop code being linked to the binary
+
+	    * Added support for MK2 MMC interface
+
+		* Added disc_Cache* functions
+
+	Modified by Chishm:
+	2006-02-05
+		* Added Supercard SD support
+
+	Modified by CyteX:
+	2006-02-26
+		* Added EFA2 support
+*/
+
+#include "disc_io.h"
+
+#ifdef NDS
+	#include <nds.h>
+#endif
+
+
+// Include known io-interfaces:
+#ifdef SUPPORT_MPCF
+ #include "io_mpcf.h"
+#endif
+
+#ifdef SUPPORT_M3CF
+ #include "io_m3cf.h"
+#endif
+
+#ifdef SUPPORT_M3SD
+ #include "io_m3sd.h"
+#endif
+
+#ifdef SUPPORT_SCCF
+ #include "io_sccf.h"
+#endif
+
+#ifdef SUPPORT_SCSD
+ #include "io_scsd.h"
+#endif
+
+#ifdef SUPPORT_FCSR
+ #include "io_fcsr.h"
+#endif
+
+#ifdef SUPPORT_NMMC
+ #include "io_nmmc.h"
+#endif
+
+#ifdef SUPPORT_EFA2
+ #include "io_efa2.h"
+#endif
+
+// Keep a pointer to the active interface
+LPIO_INTERFACE active_interface = 0;
+
+
+/*
+
+	Disc Cache functions
+	2006-02-03:
+		Added by www.neoflash.com 
+
+*/
+
+#ifdef DISC_CACHE
+
+#include <string.h>
+
+#define CACHE_FREE 0xFFFFFFFF
+	
+static u8 cacheBuffer[ DISC_CACHE_COUNT * 512 ];
+
+static struct {
+	u32 sector;
+	u32 dirty;
+	u32 count;
+} cache[ DISC_CACHE_COUNT ];
+
+static u32 disc_CacheFind(u32 sector) {
+	u32 i;
+	
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		if( cache[ i ].sector == sector )
+			return i;
+	}
+	
+	return CACHE_FREE;
+}
+
+static u32 disc_CacheFindFree(void) {
+	
+	u32 i = 0, j;
+	u32 count = -1;
+	
+	for( j = 0; j < DISC_CACHE_COUNT; j++ )	{
+
+		if( cache[ j ].sector == CACHE_FREE ) {
+			i = j;
+			break;
+		}
+
+		if( cache[ j ].count < count ) {
+			count = cache[ j ].count;
+			i = j;
+		}
+	}
+	
+	if( cache[ i ].sector != CACHE_FREE && cache[i].dirty != 0 ) {
+
+		active_interface->fn_WriteSectors( cache[ i ].sector, 1, &cacheBuffer[ i * 512 ] );
+		/* todo: handle write error here */
+
+		cache[ i ].sector = CACHE_FREE;
+		cache[ i ].dirty = 0;
+		cache[ i ].count = 0;
+	}
+
+	return i;
+}
+
+void disc_CacheInit(void)	{
+
+	u32 i;
+
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		cache[ i ].sector = CACHE_FREE;
+		cache[ i ].dirty = 0;
+		cache[ i ].count = 0;
+	}
+
+}
+
+bool disc_CacheFlush(void)	{
+
+	u32 i;
+
+	if( !active_interface )	return false;
+
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		if( cache[ i ].sector != CACHE_FREE && cache[ i ].dirty != 0 )	{
+			if( active_interface->fn_WriteSectors( cache[ i ].sector, 1, &cacheBuffer[ i * 512 ] ) == false )
+				return false;
+
+			cache[ i ].dirty = 0;
+		}
+	}
+	return true;
+}
+
+bool disc_CacheReadSector( void *buffer, u32 sector) {
+	u32 i = disc_CacheFind( sector );
+	if( i == CACHE_FREE ) {
+		i = disc_CacheFindFree();
+		cache[ i ].sector = sector;
+		if( active_interface->fn_ReadSectors( sector, 1, &cacheBuffer[ i * 512 ] ) == false )
+			return false;
+	}
+#ifdef DISK_CACHE_DMA
+		DMA3_SRC = (u32)&cacheBuffer[ i * 512 ]
+		DMA3_DEST = (u32)buffer;
+		DMA3_CR = 128 | DMA_COPY_WORDS;
+#else
+	memcpy( buffer, &cacheBuffer[ i * 512 ], 512 );
+#endif
+	cache[ i ].count++;
+	return true;
+}
+
+bool disc_CacheWriteSector( void *buffer, u32 sector ) {
+	u32 i = disc_CacheFind( sector );
+	if( i == CACHE_FREE ) {
+		i = disc_CacheFindFree();
+		cache [ i ].sector = sector;
+	}
+#ifdef DISK_CACHE_DMA
+		DMA3_SRC = (u32)buffer;
+		DMA3_DEST = (u32)&cacheBuffer[ i * 512 ];
+		DMA3_CR = 128 | DMA_COPY_WORDS;
+#else
+	memcpy( &cacheBuffer[ i * 512 ], buffer, 512 );
+#endif
+	cache[ i ].dirty=1;
+	cache[ i ].count++;
+	return true;
+}
+
+#endif
+
+/*
+
+	Hardware level disc funtions
+
+*/
+
+bool disc_setGbaSlotInterface (void)
+{
+	// If running on an NDS, make sure the correct CPU can access
+	// the GBA cart. First implemented by SaTa.
+#ifdef NDS
+ #ifdef ARM9
+//	WAIT_CR &= ~(0x8080);
+ #endif
+ #ifdef ARM7
+//	WAIT_CR |= (0x8080);
+ #endif
+#endif
+
+#ifdef SUPPORT_M3CF
+	// check if we have a M3 perfect CF plugged in
+	active_interface = M3CF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set M3 CF as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_M3SD
+	// check if we have a M3 perfect SD plugged in
+	active_interface = M3SD_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set M3 SD as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_MPCF
+	// check if we have a GBA Movie Player plugged in
+	active_interface = MPCF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set GBAMP as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_SCCF
+	// check if we have a SuperCard CF plugged in
+	active_interface = SCCF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set SC CF as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_SCSD
+	// check if we have a SuperCard SD plugged in
+	active_interface = SCSD_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set SC SD as default IO
+		return true ;
+	} ;
+#endif
+
+
+#ifdef SUPPORT_EFA2
+	// check if we have a EFA2 plugged in
+	active_interface = EFA2_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_FCSR
+	// check if we have a GBA Flash Cart plugged in
+	active_interface = FCSR_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set FC as default IO
+		return true ;
+	} ;
+#endif
+
+	return false;
+}
+
+#ifdef NDS
+// Check the DS card slot for a valid memory card interface
+// If an interface is found, it is set as the default interace
+// and it returns true. Otherwise the default interface is left
+// untouched and it returns false.
+bool disc_setDsSlotInterface (void)
+{
+#ifdef ARM9
+	WAIT_CR &= ~(1<<11);
+#endif
+#ifdef ARM7
+	WAIT_CR |= (1<<11);
+#endif
+
+#ifdef SUPPORT_NMMC
+	// check if we have a Neoflash MK2 / MK3 plugged in
+	active_interface = NMMC_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set Neoflash MK2 / MK3 as default IO
+		return true ;
+	} ;
+#endif
+
+	return false;
+}
+#endif
+
+
+bool disc_Init(void) 
+{
+#ifdef DISC_CACHE
+	disc_CacheInit();
+#endif
+
+
+	if (active_interface != 0) {
+		return true;
+	}
+
+#ifdef NDS
+	if (disc_setDsSlotInterface()) {
+		return true;
+	}
+#endif
+
+	if (disc_setGbaSlotInterface()) {
+		return true;
+	}
+
+	// could not find a working IO Interface
+	active_interface = 0 ;
+	return false ;
+} 
+
+bool disc_IsInserted(void) 
+{
+	if (active_interface) return active_interface->fn_IsInserted() ;
+	return false ;
+} 
+
+bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer) 
+{
+#ifdef DISC_CACHE
+	u8 *p=(u8*)buffer;
+	u32 i;
+	u32 inumSecs=numSecs;
+	if(numSecs==0)
+		inumSecs=256;
+	for( i = 0; i<inumSecs; i++)	{
+		if( disc_CacheReadSector( &p[i*512], sector + i ) == false )
+			return false;
+	}
+	return true;
+#else
+	if (active_interface) return active_interface->fn_ReadSectors(sector,numSecs,buffer) ;
+	return false ;
+#endif
+} 
+
+bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer) 
+{
+#ifdef DISC_CACHE
+	u8 *p=(u8*)buffer;
+	u32 i;
+	u32 inumSecs=numSecs;
+	if(numSecs==0)
+		inumSecs=256;
+	for( i = 0; i<inumSecs; i++)	{
+		if( disc_CacheWriteSector( &p[i*512], sector + i ) == false )
+			return false;
+	}
+	return true;
+#else
+	if (active_interface) return active_interface->fn_WriteSectors(sector,numSecs,buffer) ;
+	return false ;
+#endif
+} 
+
+bool disc_ClearStatus(void) 
+{
+	if (active_interface) return active_interface->fn_ClearStatus() ;
+	return false ;
+} 
+
+bool disc_Shutdown(void) 
+{
+#ifdef DISC_CACHE
+	disc_CacheFlush();
+#endif
+	if (active_interface) active_interface->fn_Shutdown() ;
+	active_interface = 0 ;
+	return true ;
+} 
+
+u32	disc_HostType (void)
+{
+	if (active_interface) {
+		return active_interface->ul_ioType;
+	} else {
+		return 0;
+	}
+}
+
+/*
+
+	disc_io.c
+
+	uniformed io-interface to work with Chishm's FAT library
+
+	Written by MightyMax
+  
+	Modified by Chishm:
+	2005-11-06
+		* Added WAIT_CR modifications for NDS
+
+	Modified by www.neoflash.com:
+	2006-02-03
+		* Added SUPPORT_* defines, comment out any of the SUPPORT_* defines in disc_io.h to remove support
+		  for the given interface and stop code being linked to the binary
+
+	    * Added support for MK2 MMC interface
+
+		* Added disc_Cache* functions
+
+	Modified by Chishm:
+	2006-02-05
+		* Added Supercard SD support
+
+	Modified by CyteX:
+	2006-02-26
+		* Added EFA2 support
+*/
+
+#include "disc_io.h"
+
+#ifdef NDS
+	#include <nds.h>
+#endif
+
+
+// Include known io-interfaces:
+#ifdef SUPPORT_MPCF
+ #include "io_mpcf.h"
+#endif
+
+#ifdef SUPPORT_M3CF
+ #include "io_m3cf.h"
+#endif
+
+#ifdef SUPPORT_M3SD
+ #include "io_m3sd.h"
+#endif
+
+#ifdef SUPPORT_SCCF
+ #include "io_sccf.h"
+#endif
+
+#ifdef SUPPORT_SCSD
+ #include "io_scsd.h"
+#endif
+
+#ifdef SUPPORT_FCSR
+ #include "io_fcsr.h"
+#endif
+
+#ifdef SUPPORT_NMMC
+ #include "io_nmmc.h"
+#endif
+
+#ifdef SUPPORT_EFA2
+ #include "io_efa2.h"
+#endif
+
+// Keep a pointer to the active interface
+LPIO_INTERFACE active_interface = 0;
+
+
+/*
+
+	Disc Cache functions
+	2006-02-03:
+		Added by www.neoflash.com 
+
+*/
+
+#ifdef DISC_CACHE
+
+#include <string.h>
+
+#define CACHE_FREE 0xFFFFFFFF
+	
+static u8 cacheBuffer[ DISC_CACHE_COUNT * 512 ];
+
+static struct {
+	u32 sector;
+	u32 dirty;
+	u32 count;
+} cache[ DISC_CACHE_COUNT ];
+
+static u32 disc_CacheFind(u32 sector) {
+	u32 i;
+	
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		if( cache[ i ].sector == sector )
+			return i;
+	}
+	
+	return CACHE_FREE;
+}
+
+static u32 disc_CacheFindFree(void) {
+	
+	u32 i = 0, j;
+	u32 count = -1;
+	
+	for( j = 0; j < DISC_CACHE_COUNT; j++ )	{
+
+		if( cache[ j ].sector == CACHE_FREE ) {
+			i = j;
+			break;
+		}
+
+		if( cache[ j ].count < count ) {
+			count = cache[ j ].count;
+			i = j;
+		}
+	}
+	
+	if( cache[ i ].sector != CACHE_FREE && cache[i].dirty != 0 ) {
+
+		active_interface->fn_WriteSectors( cache[ i ].sector, 1, &cacheBuffer[ i * 512 ] );
+		/* todo: handle write error here */
+
+		cache[ i ].sector = CACHE_FREE;
+		cache[ i ].dirty = 0;
+		cache[ i ].count = 0;
+	}
+
+	return i;
+}
+
+void disc_CacheInit(void)	{
+
+	u32 i;
+
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		cache[ i ].sector = CACHE_FREE;
+		cache[ i ].dirty = 0;
+		cache[ i ].count = 0;
+	}
+
+}
+
+bool disc_CacheFlush(void)	{
+
+	u32 i;
+
+	if( !active_interface )	return false;
+
+	for( i = 0; i < DISC_CACHE_COUNT; i++ )	{
+		if( cache[ i ].sector != CACHE_FREE && cache[ i ].dirty != 0 )	{
+			if( active_interface->fn_WriteSectors( cache[ i ].sector, 1, &cacheBuffer[ i * 512 ] ) == false )
+				return false;
+
+			cache[ i ].dirty = 0;
+		}
+	}
+	return true;
+}
+
+bool disc_CacheReadSector( void *buffer, u32 sector) {
+	u32 i = disc_CacheFind( sector );
+	if( i == CACHE_FREE ) {
+		i = disc_CacheFindFree();
+		cache[ i ].sector = sector;
+		if( active_interface->fn_ReadSectors( sector, 1, &cacheBuffer[ i * 512 ] ) == false )
+			return false;
+	}
+#ifdef DISK_CACHE_DMA
+		DMA3_SRC = (u32)&cacheBuffer[ i * 512 ]
+		DMA3_DEST = (u32)buffer;
+		DMA3_CR = 128 | DMA_COPY_WORDS;
+#else
+	memcpy( buffer, &cacheBuffer[ i * 512 ], 512 );
+#endif
+	cache[ i ].count++;
+	return true;
+}
+
+bool disc_CacheWriteSector( void *buffer, u32 sector ) {
+	u32 i = disc_CacheFind( sector );
+	if( i == CACHE_FREE ) {
+		i = disc_CacheFindFree();
+		cache [ i ].sector = sector;
+	}
+#ifdef DISK_CACHE_DMA
+		DMA3_SRC = (u32)buffer;
+		DMA3_DEST = (u32)&cacheBuffer[ i * 512 ];
+		DMA3_CR = 128 | DMA_COPY_WORDS;
+#else
+	memcpy( &cacheBuffer[ i * 512 ], buffer, 512 );
+#endif
+	cache[ i ].dirty=1;
+	cache[ i ].count++;
+	return true;
+}
+
+#endif
+
+/*
+
+	Hardware level disc funtions
+
+*/
+
+bool disc_setGbaSlotInterface (void)
+{
+	// If running on an NDS, make sure the correct CPU can access
+	// the GBA cart. First implemented by SaTa.
+#ifdef NDS
+ #ifdef ARM9
+//	WAIT_CR &= ~(0x8080);
+ #endif
+ #ifdef ARM7
+//	WAIT_CR |= (0x8080);
+ #endif
+#endif
+
+#ifdef SUPPORT_M3CF
+	// check if we have a M3 perfect CF plugged in
+	active_interface = M3CF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set M3 CF as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_M3SD
+	// check if we have a M3 perfect SD plugged in
+	active_interface = M3SD_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set M3 SD as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_MPCF
+	// check if we have a GBA Movie Player plugged in
+	active_interface = MPCF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set GBAMP as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_SCCF
+	// check if we have a SuperCard CF plugged in
+	active_interface = SCCF_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set SC CF as default IO
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_SCSD
+	// check if we have a SuperCard SD plugged in
+	active_interface = SCSD_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set SC SD as default IO
+		return true ;
+	} ;
+#endif
+
+
+#ifdef SUPPORT_EFA2
+	// check if we have a EFA2 plugged in
+	active_interface = EFA2_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		return true ;
+	} ;
+#endif
+
+#ifdef SUPPORT_FCSR
+	// check if we have a GBA Flash Cart plugged in
+	active_interface = FCSR_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set FC as default IO
+		return true ;
+	} ;
+#endif
+
+	return false;
+}
+
+#ifdef NDS
+// Check the DS card slot for a valid memory card interface
+// If an interface is found, it is set as the default interace
+// and it returns true. Otherwise the default interface is left
+// untouched and it returns false.
+bool disc_setDsSlotInterface (void)
+{
+#ifdef ARM9
+	WAIT_CR &= ~(1<<11);
+#endif
+#ifdef ARM7
+	WAIT_CR |= (1<<11);
+#endif
+
+#ifdef SUPPORT_NMMC
+	// check if we have a Neoflash MK2 / MK3 plugged in
+	active_interface = NMMC_GetInterface() ;
+	if (active_interface->fn_StartUp())
+	{
+		// set Neoflash MK2 / MK3 as default IO
+		return true ;
+	} ;
+#endif
+
+	return false;
+}
+#endif
+
+
+bool disc_Init(void) 
+{
+#ifdef DISC_CACHE
+	disc_CacheInit();
+#endif
+
+
+	if (active_interface != 0) {
+		return true;
+	}
+
+#ifdef NDS
+	if (disc_setDsSlotInterface()) {
+		return true;
+	}
+#endif
+
+	if (disc_setGbaSlotInterface()) {
+		return true;
+	}
+
+	// could not find a working IO Interface
+	active_interface = 0 ;
+	return false ;
+} 
+
+bool disc_IsInserted(void) 
+{
+	if (active_interface) return active_interface->fn_IsInserted() ;
+	return false ;
+} 
+
+bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer) 
+{
+#ifdef DISC_CACHE
+	u8 *p=(u8*)buffer;
+	u32 i;
+	u32 inumSecs=numSecs;
+	if(numSecs==0)
+		inumSecs=256;
+	for( i = 0; i<inumSecs; i++)	{
+		if( disc_CacheReadSector( &p[i*512], sector + i ) == false )
+			return false;
+	}
+	return true;
+#else
+	if (active_interface) return active_interface->fn_ReadSectors(sector,numSecs,buffer) ;
+	return false ;
+#endif
+} 
+
+bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer) 
+{
+#ifdef DISC_CACHE
+	u8 *p=(u8*)buffer;
+	u32 i;
+	u32 inumSecs=numSecs;
+	if(numSecs==0)
+		inumSecs=256;
+	for( i = 0; i<inumSecs; i++)	{
+		if( disc_CacheWriteSector( &p[i*512], sector + i ) == false )
+			return false;
+	}
+	return true;
+#else
+	if (active_interface) return active_interface->fn_WriteSectors(sector,numSecs,buffer) ;
+	return false ;
+#endif
+} 
+
+bool disc_ClearStatus(void) 
+{
+	if (active_interface) return active_interface->fn_ClearStatus() ;
+	return false ;
+} 
+
+bool disc_Shutdown(void) 
+{
+#ifdef DISC_CACHE
+	disc_CacheFlush();
+#endif
+	if (active_interface) active_interface->fn_Shutdown() ;
+	active_interface = 0 ;
+	return true ;
+} 
+
+u32	disc_HostType (void)
+{
+	if (active_interface) {
+		return active_interface->ul_ioType;
+	} else {
+		return 0;
+	}
+}
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,364 @@
+#ifndef DISC_IO_H
+#define DISC_IO_H
+
+//----------------------------------------------------------------------
+// Customisable features
+
+// Use DMA to read the card, remove this line to use normal reads/writes
+// #define _CF_USE_DMA
+
+// Allow buffers not aligned to 16 bits when reading files. 
+// Note that this will slow down access speed, so only use if you have to.
+// It is also incompatible with DMA
+//#define _CF_ALLOW_UNALIGNED
+
+// Device support options, added by www.neoflash.com
+
+#define SUPPORT_NMMC		// comment out this line to remove Neoflash MK2 MMC Card support
+#define SUPPORT_MPCF		// comment out this line to remove GBA Movie Player support
+#define SUPPORT_M3CF		// comment out this line to remove M3 Perfect CF support
+#define SUPPORT_M3SD		// comment out this line to remove M3 Perfect SD support
+#define SUPPORT_SCCF		// comment out this line to remove Supercard CF support
+#define SUPPORT_SCSD		// comment out this line to remove Supercard SD support
+//#define SUPPORT_EFA2		// comment out this line to remove EFA2 linker support
+#define SUPPORT_FCSR		// comment out this line to remove GBA Flash Cart support
+
+// Disk caching options, added by www.neoflash.com
+// Each additional sector cache uses 512 bytes of memory
+// Disk caching is disabled on GBA to conserve memory
+
+#define DISC_CACHE				// uncomment this line to enable disc caching
+#define DISC_CACHE_COUNT	16	// maximum number of sectors to cache (512 bytes per sector)
+//#define DISK_CACHE_DMA		// use DMA for cache copies. If this is enabled, the data buffers must be word aligned
+
+
+//----------------------------------------------------------------------
+
+#if defined _CF_USE_DMA && defined _CF_ALLOW_UNALIGNED
+ #error You can't use both DMA and unaligned memory
+#endif
+
+// When compiling for NDS, make sure NDS is defined
+#ifndef NDS
+ #if defined ARM9 || defined ARM7
+  #define NDS
+ #endif
+#endif
+
+#ifdef NDS
+ #include <nds/jtypes.h>
+#else
+ #include "gba_types.h"
+#endif
+
+// Disable NDS specific hardware and features if running on a GBA
+#ifndef NDS 
+ #undef SUPPORT_NMMC
+ #undef DISC_CACHE
+#endif
+
+/*
+
+	Interface for host program
+
+*/
+
+#define BYTE_PER_READ 512
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------------
+disc_Init
+Detects the inserted hardware and initialises it if necessary
+bool return OUT:  true if a suitable device was found
+-----------------------------------------------------------------*/
+extern bool disc_Init(void) ;
+
+/*-----------------------------------------------------------------
+disc_IsInserted
+Is a usable disc inserted?
+bool return OUT:  true if a disc is inserted
+-----------------------------------------------------------------*/
+extern bool disc_IsInserted(void) ;
+
+/*-----------------------------------------------------------------
+disc_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on disc to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer) ;
+#define disc_ReadSector(sector,buffer)	disc_ReadSectors(sector,1,buffer)
+
+/*-----------------------------------------------------------------
+disc_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on disc to write
+u8 numSecs IN: number of 512 byte sectors to write	,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer) ;
+#define disc_WriteSector(sector,buffer)	disc_WriteSectors(sector,1,buffer)
+
+/*-----------------------------------------------------------------
+disc_ClearStatus
+Tries to make the disc go back to idle mode
+bool return OUT:  true if the disc is idle
+-----------------------------------------------------------------*/
+extern bool disc_ClearStatus(void) ;
+
+/*-----------------------------------------------------------------
+disc_Shutdown
+unload the disc interface
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_Shutdown(void) ;
+
+/*-----------------------------------------------------------------
+disc_HostType
+Returns a unique u32 number identifying the host type
+u32 return OUT: 0 if no host initialised, else the identifier of
+	the host
+-----------------------------------------------------------------*/
+extern u32 disc_HostType(void);
+
+/*-----------------------------------------------------------------
+disc_CacheFlush
+Flushes any cache writes to disc
+bool return OUT: true if successful, false if an error occurs
+Added by www.neoflash.com
+-----------------------------------------------------------------*/
+#ifdef DISC_CACHE
+extern bool disc_CacheFlush(void);
+#else
+static inline bool disc_CacheFlush(void)
+{
+	return true;
+}
+#endif // DISC_CACHE
+
+
+/*
+
+	Interface for IO libs
+
+*/
+
+#define FEATURE_MEDIUM_CANREAD		0x00000001
+#define FEATURE_MEDIUM_CANWRITE		0x00000002
+#define FEATURE_SLOT_GBA			0x00000010
+#define FEATURE_SLOT_NDS			0x00000020
+
+typedef bool (* FN_MEDIUM_STARTUP)(void) ;
+typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
+typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u8 numSecs, void* buffer) ;
+typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u8 numSecs, void* buffer) ;
+typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
+typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
+
+
+typedef struct {
+	unsigned long			ul_ioType ;
+	unsigned long			ul_Features ;
+	FN_MEDIUM_STARTUP		fn_StartUp ;
+	FN_MEDIUM_ISINSERTED	fn_IsInserted ;
+	FN_MEDIUM_READSECTORS	fn_ReadSectors ;
+	FN_MEDIUM_WRITESECTORS	fn_WriteSectors ;
+	FN_MEDIUM_CLEARSTATUS	fn_ClearStatus ;
+	FN_MEDIUM_SHUTDOWN		fn_Shutdown ;
+} IO_INTERFACE, *LPIO_INTERFACE ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// define DISC_IO_H
+#ifndef DISC_IO_H
+#define DISC_IO_H
+
+//----------------------------------------------------------------------
+// Customisable features
+
+// Use DMA to read the card, remove this line to use normal reads/writes
+// #define _CF_USE_DMA
+
+// Allow buffers not aligned to 16 bits when reading files. 
+// Note that this will slow down access speed, so only use if you have to.
+// It is also incompatible with DMA
+//#define _CF_ALLOW_UNALIGNED
+
+// Device support options, added by www.neoflash.com
+
+#define SUPPORT_NMMC		// comment out this line to remove Neoflash MK2 MMC Card support
+#define SUPPORT_MPCF		// comment out this line to remove GBA Movie Player support
+#define SUPPORT_M3CF		// comment out this line to remove M3 Perfect CF support
+#define SUPPORT_M3SD		// comment out this line to remove M3 Perfect SD support
+#define SUPPORT_SCCF		// comment out this line to remove Supercard CF support
+#define SUPPORT_SCSD		// comment out this line to remove Supercard SD support
+//#define SUPPORT_EFA2		// comment out this line to remove EFA2 linker support
+#define SUPPORT_FCSR		// comment out this line to remove GBA Flash Cart support
+
+// Disk caching options, added by www.neoflash.com
+// Each additional sector cache uses 512 bytes of memory
+// Disk caching is disabled on GBA to conserve memory
+
+#define DISC_CACHE				// uncomment this line to enable disc caching
+#define DISC_CACHE_COUNT	16	// maximum number of sectors to cache (512 bytes per sector)
+//#define DISK_CACHE_DMA		// use DMA for cache copies. If this is enabled, the data buffers must be word aligned
+
+
+//----------------------------------------------------------------------
+
+#if defined _CF_USE_DMA && defined _CF_ALLOW_UNALIGNED
+ #error You can't use both DMA and unaligned memory
+#endif
+
+// When compiling for NDS, make sure NDS is defined
+#ifndef NDS
+ #if defined ARM9 || defined ARM7
+  #define NDS
+ #endif
+#endif
+
+#ifdef NDS
+ #include <nds/jtypes.h>
+#else
+ #include "gba_types.h"
+#endif
+
+// Disable NDS specific hardware and features if running on a GBA
+#ifndef NDS 
+ #undef SUPPORT_NMMC
+ #undef DISC_CACHE
+#endif
+
+/*
+
+	Interface for host program
+
+*/
+
+#define BYTE_PER_READ 512
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------------------------
+disc_Init
+Detects the inserted hardware and initialises it if necessary
+bool return OUT:  true if a suitable device was found
+-----------------------------------------------------------------*/
+extern bool disc_Init(void) ;
+
+/*-----------------------------------------------------------------
+disc_IsInserted
+Is a usable disc inserted?
+bool return OUT:  true if a disc is inserted
+-----------------------------------------------------------------*/
+extern bool disc_IsInserted(void) ;
+
+/*-----------------------------------------------------------------
+disc_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on disc to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer) ;
+#define disc_ReadSector(sector,buffer)	disc_ReadSectors(sector,1,buffer)
+
+/*-----------------------------------------------------------------
+disc_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on disc to write
+u8 numSecs IN: number of 512 byte sectors to write	,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer) ;
+#define disc_WriteSector(sector,buffer)	disc_WriteSectors(sector,1,buffer)
+
+/*-----------------------------------------------------------------
+disc_ClearStatus
+Tries to make the disc go back to idle mode
+bool return OUT:  true if the disc is idle
+-----------------------------------------------------------------*/
+extern bool disc_ClearStatus(void) ;
+
+/*-----------------------------------------------------------------
+disc_Shutdown
+unload the disc interface
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+extern bool disc_Shutdown(void) ;
+
+/*-----------------------------------------------------------------
+disc_HostType
+Returns a unique u32 number identifying the host type
+u32 return OUT: 0 if no host initialised, else the identifier of
+	the host
+-----------------------------------------------------------------*/
+extern u32 disc_HostType(void);
+
+/*-----------------------------------------------------------------
+disc_CacheFlush
+Flushes any cache writes to disc
+bool return OUT: true if successful, false if an error occurs
+Added by www.neoflash.com
+-----------------------------------------------------------------*/
+#ifdef DISC_CACHE
+extern bool disc_CacheFlush(void);
+#else
+static inline bool disc_CacheFlush(void)
+{
+	return true;
+}
+#endif // DISC_CACHE
+
+
+/*
+
+	Interface for IO libs
+
+*/
+
+#define FEATURE_MEDIUM_CANREAD		0x00000001
+#define FEATURE_MEDIUM_CANWRITE		0x00000002
+#define FEATURE_SLOT_GBA			0x00000010
+#define FEATURE_SLOT_NDS			0x00000020
+
+typedef bool (* FN_MEDIUM_STARTUP)(void) ;
+typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
+typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u8 numSecs, void* buffer) ;
+typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u8 numSecs, void* buffer) ;
+typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
+typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
+
+
+typedef struct {
+	unsigned long			ul_ioType ;
+	unsigned long			ul_Features ;
+	FN_MEDIUM_STARTUP		fn_StartUp ;
+	FN_MEDIUM_ISINSERTED	fn_IsInserted ;
+	FN_MEDIUM_READSECTORS	fn_ReadSectors ;
+	FN_MEDIUM_WRITESECTORS	fn_WriteSectors ;
+	FN_MEDIUM_CLEARSTATUS	fn_ClearStatus ;
+	FN_MEDIUM_SHUTDOWN		fn_Shutdown ;
+} IO_INTERFACE, *LPIO_INTERFACE ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	// define DISC_IO_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/disc_io.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,6660 @@
+/*
+	gba_nds_fat.c
+	By chishm (Michael Chisholm)
+
+	Routines for reading a compact flash card
+	using the GBA Movie Player or M3.
+
+	Some FAT routines are based on those in fat.c, which
+	is part of avrlib by Pascal Stang.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+//---------------------------------------------------------------
+// Includes
+
+#include "gba_nds_fat.h"
+#include "disc_io.h"
+#include <string.h>
+#ifdef NDS
+ #include <nds/ipc.h>	// Time on the NDS
+#endif
+//----------------------------------------------------------------
+// Data	types
+#ifndef	NULL
+ #define	NULL	0
+#endif
+
+//----------------------------------------------------------------
+// NDS memory access control register
+#ifdef NDS
+ #ifndef WAIT_CR
+  #define WAIT_CR (*(vu16*)0x04000204)
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// Appropriate placement of CF functions and data
+#ifdef NDS
+ #define _VARS_IN_RAM 
+#else
+ #define _VARS_IN_RAM __attribute__ ((section (".sbss")))
+#endif
+
+
+//-----------------------------------------------------------------
+// FAT constants
+#define CLUSTER_EOF_16	0xFFFF
+#define	CLUSTER_EOF	0x0FFFFFFF
+#define CLUSTER_FREE	0x0000
+#define CLUSTER_FIRST	0x0002
+
+#define FILE_LAST 0x00
+#define FILE_FREE 0xE5
+
+#define FAT16_ROOT_DIR_CLUSTER 0x00
+
+
+//-----------------------------------------------------------------
+// long file name constants
+#define LFN_END 0x40
+#define LFN_DEL 0x80
+
+//-----------------------------------------------------------------
+// Data Structures
+
+// Take care of packing for GCC - it doesn't obey pragma pack()
+// properly for ARM targets.
+#ifdef __GNUC__
+ #define __PACKED __attribute__ ((__packed__))
+#else
+ #define __PACKED 
+ #pragma pack(1)
+#endif
+
+// Boot Sector - must be packed
+typedef struct
+{
+	u8	jmpBoot[3];
+	u8	OEMName[8];
+	// BIOS Parameter Block
+	u16	bytesPerSector;
+	u8	sectorsPerCluster;
+	u16	reservedSectors;
+	u8	numFATs;
+	u16	rootEntries;
+	u16	numSectorsSmall;
+	u8	mediaDesc;
+	u16	sectorsPerFAT;
+	u16	sectorsPerTrk;
+	u16	numHeads;
+	u32	numHiddenSectors;
+	u32	numSectors;
+	union	// Different types of extended BIOS Parameter Block for FAT16 and FAT32
+	{
+		struct  
+		{
+			// Ext BIOS Parameter Block for FAT16
+			u8	driveNumber;
+			u8	reserved1;
+			u8	extBootSig;
+			u32	volumeID;
+			u8	volumeLabel[11];
+			u8	fileSysType[8];
+			// Bootcode
+			u8	bootCode[448];
+		}	__PACKED fat16;
+		struct  
+		{
+			// FAT32 extended block
+			u32	sectorsPerFAT32;
+			u16	extFlags;
+			u16	fsVer;
+			u32	rootClus;
+			u16	fsInfo;
+			u16	bkBootSec;
+			u8	reserved[12];
+			// Ext BIOS Parameter Block for FAT16
+			u8	driveNumber;
+			u8	reserved1;
+			u8	extBootSig;
+			u32	volumeID;
+			u8	volumeLabel[11];
+			u8	fileSysType[8];
+			// Bootcode
+			u8	bootCode[420];
+		}	__PACKED fat32;
+	}	__PACKED extBlock;
+
+	u16	bootSig;
+
+}	__PACKED BOOT_SEC;
+
+// Directory entry - must be packed
+typedef struct
+{
+	u8	name[8];
+	u8	ext[3];
+	u8	attrib;
+	u8	reserved;
+	u8	cTime_ms;
+	u16	cTime;
+	u16	cDate;
+	u16	aDate;
+	u16	startClusterHigh;
+	u16	mTime;
+	u16	mDate;
+	u16	startCluster;
+	u32	fileSize;
+}	__PACKED DIR_ENT;
+
+// Long file name directory entry - must be packed
+typedef struct
+{
+	u8 ordinal;	// Position within LFN
+	u16 char0;	
+	u16 char1;
+	u16 char2;
+	u16 char3;
+	u16 char4;
+	u8 flag;	// Should be equal to ATTRIB_LFN
+	u8 reserved1;	// Always 0x00
+	u8 checkSum;	// Checksum of short file name (alias)
+	u16 char5;
+	u16 char6;
+	u16 char7;
+	u16 char8;
+	u16 char9;
+	u16 char10;
+	u16 reserved2;	// Always 0x0000
+	u16 char11;
+	u16 char12;
+}	__PACKED DIR_ENT_LFN;
+
+const char lfn_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E}; 
+
+// End of packed structs
+#ifdef __PACKED
+ #undef __PACKED
+#endif
+#ifndef __GNUC__
+ #pragma pack()
+#endif
+
+//-----------------------------------------------------------------
+// Global Variables
+
+// _VARS_IN_RAM variables are stored in the largest section of WRAM 
+// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA
+
+// Files
+_VARS_IN_RAM FAT_FILE openFiles[MAX_FILES_OPEN];
+
+// Long File names
+_VARS_IN_RAM char lfnName[MAX_FILENAME_LENGTH];
+bool lfnExists;
+
+// Locations on card
+int filesysRootDir;
+int filesysRootDirClus;
+int filesysFAT;
+int filesysSecPerFAT;
+int filesysNumSec;
+int filesysData;
+int filesysBytePerSec;
+int filesysSecPerClus;
+int filesysBytePerClus;
+
+FS_TYPE filesysType = FS_UNKNOWN;
+u32 filesysTotalSize;
+
+// Info about FAT
+u32 fatLastCluster;
+u32 fatFirstFree;
+
+// fatBuffer used to reduce wear on the CF card from multiple writes
+_VARS_IN_RAM char fatBuffer[BYTE_PER_READ];
+u32 fatBufferCurSector;
+
+// Current working directory
+u32 curWorkDirCluster;
+
+// Position of the directory entry last retreived with FAT_GetDirEntry
+u32 wrkDirCluster;
+int wrkDirSector;
+int wrkDirOffset;
+
+// Global sector buffer to save on stack space
+_VARS_IN_RAM unsigned char globalBuffer[BYTE_PER_READ];
+
+//-----------------------------------------------------------------
+// Functions contained in this file - predeclarations
+char ucase (char character);
+u16 getRTCtoFileTime (void);
+u16 getRTCtoFileDate (void);
+
+bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry);
+bool FAT_ClearLinks (u32 cluster);
+DIR_ENT FAT_DirEntFromPath (const char* path);
+u32 FAT_FirstFreeCluster(void);
+DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin);
+u32 FAT_LinkFreeCluster(u32 cluster);
+u32 FAT_NextCluster(u32 cluster);
+bool FAT_WriteFatEntry (u32 cluster, u32 value);
+bool FAT_GetFilename (DIR_ENT dirEntry, char* alias);
+
+bool FAT_InitFiles (void);
+bool FAT_FreeFiles (void);
+int FAT_remove (const char* path);
+bool FAT_chdir (const char* path);
+FILE_TYPE FAT_FindFirstFile (char* filename);
+FILE_TYPE FAT_FindNextFile (char* filename);
+FILE_TYPE FAT_FileExists (const char* filename);
+bool FAT_GetAlias (char* alias);
+bool FAT_GetLongFilename (char* filename);
+u32 FAT_GetFileSize (void);
+u32 FAT_GetFileCluster (void);
+
+FAT_FILE* FAT_fopen(const char* path, const char* mode);
+bool FAT_fclose (FAT_FILE* file);
+bool FAT_feof(FAT_FILE* file);
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin);
+u32 FAT_ftell (FAT_FILE* file);
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file);
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file);
+char FAT_fgetc (FAT_FILE* file);
+char FAT_fputc (char c, FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+ucase
+Returns the uppercase version of the given char
+char IN: a character
+char return OUT: uppercase version of character
+-----------------------------------------------------------------*/
+char ucase (char character)
+{
+	if ((character > 0x60) && (character < 0x7B))
+		character = character - 0x20;
+	return (character);
+}
+
+
+/*-----------------------------------------------------------------
+getRTCtoFileTime and getRTCtoFileDate
+Returns the time / date in Dir Entry styled format
+u16 return OUT: time / date in Dir Entry styled format
+-----------------------------------------------------------------*/
+u16 getRTCtoFileTime (void)
+{
+#ifdef NDS
+	return (
+		( ( (IPC->rtc_hours > 11 ? IPC->rtc_hours - 40 : IPC->rtc_hours) & 0x1F) << 11) |
+		( (IPC->rtc_minutes & 0x3F) << 5) |
+		( (IPC->rtc_seconds >> 1) & 0x1F) );
+#else
+	return 0;
+#endif
+}
+
+u16 getRTCtoFileDate (void)
+{
+#ifdef NDS
+	return ( 
+		( ((IPC->rtc_year + 20) & 0x7F) <<9) |
+		( (IPC->rtc_month & 0xF) << 5) |
+		(IPC->rtc_day & 0x1F) );
+#else
+	return 0;
+#endif
+}
+
+
+/*-----------------------------------------------------------------
+Disc level FAT routines
+-----------------------------------------------------------------*/
+#define FAT_ClustToSect(m) \
+	(((m-2) * filesysSecPerClus) + filesysData)
+
+/*-----------------------------------------------------------------
+FAT_NextCluster
+Internal function - gets the cluster linked from input cluster
+-----------------------------------------------------------------*/
+u32 FAT_NextCluster(u32 cluster)
+{
+	u32 nextCluster = CLUSTER_FREE;
+	u32 sector;
+	int offset;
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			nextCluster = CLUSTER_FREE;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			nextCluster = ((u8*)fatBuffer)[offset];
+			offset++;
+			
+			if (offset >= BYTE_PER_READ) {
+				offset = 0;
+				fatBufferCurSector++;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+			
+			nextCluster |= (((u8*)fatBuffer)[offset]) << 8;
+			
+			if (cluster & 0x01) {
+				nextCluster = nextCluster >> 4;
+			} else 	{
+				nextCluster &= 0x0FFF;
+			}
+			
+			if (nextCluster >= 0x0FF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// read the nextCluster value
+			nextCluster = ((u16*)fatBuffer)[offset];
+			
+			if (nextCluster >= 0xFFF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// read the nextCluster value
+			nextCluster = (((u32*)fatBuffer)[offset]) & 0x0FFFFFFF;
+			
+			if (nextCluster >= 0x0FFFFFF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+			break;
+			
+		default:
+			nextCluster = CLUSTER_FREE;
+			break;
+	}
+	
+	return nextCluster;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_WriteFatEntry
+Internal function - writes FAT information about a cluster
+-----------------------------------------------------------------*/
+bool FAT_WriteFatEntry (u32 cluster, u32 value)
+{
+	u32 sector;
+	int offset;
+
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+	{
+		return false;
+	}
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			return false;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			if (cluster & 0x01) {
+
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4);
+
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				((u8*)fatBuffer)[offset] =  (value & 0x0FF0) >> 4;
+
+			} else {
+			
+				((u8*)fatBuffer)[offset] = value & 0xFF;
+		
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F);
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			((u16*)fatBuffer)[offset] = (value & 0xFFFF);
+
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			(((u32*)fatBuffer)[offset]) =  value;
+
+			break;
+			
+		default:
+			return false;
+			break;
+	}
+	
+	// write the buffer back to disc
+	disc_WriteSector(fatBufferCurSector, fatBuffer);
+			
+	return true;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_ReadWriteFatEntryBuffered
+Internal function - writes FAT information about a cluster to a 
+ buffer that should then be flushed to disc using 
+ FAT_WriteFatEntryFlushBuffer()
+ Call FAT_WriteFatEntry first so as not to ruin the disc.
+ Also returns the entry being replaced
+-----------------------------------------------------------------*/
+u32 FAT_ReadWriteFatEntryBuffered (u32 cluster, u32 value)
+{
+	u32 sector;
+	int offset;
+	u32 oldValue;
+
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+		return CLUSTER_FREE;
+
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			oldValue = CLUSTER_FREE;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			if (cluster & 0x01) {
+
+				oldValue = (((u8*)fatBuffer)[offset] & 0xF0) >> 4;
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4);
+
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				oldValue |= ((((u8*)fatBuffer)[offset]) << 4) & 0x0FF0;
+				((u8*)fatBuffer)[offset] =  (value & 0x0FF0) >> 4;
+
+			} else {
+			
+				oldValue = ((u8*)fatBuffer)[offset] & 0xFF;
+				((u8*)fatBuffer)[offset] = value & 0xFF;
+		
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				oldValue |= (((u8*)fatBuffer)[offset] & 0x0F) << 8;
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F);
+			}
+
+			if (oldValue >= 0x0FF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			} 
+
+			// write the value to the FAT buffer
+			oldValue = ((u16*)fatBuffer)[offset];
+			((u16*)fatBuffer)[offset] = value;
+
+			if (oldValue >= 0xFFF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			oldValue = ((u32*)fatBuffer)[offset];
+			((u32*)fatBuffer)[offset] =  value;
+
+			if (oldValue >= 0x0FFFFFF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		default:
+			oldValue = CLUSTER_FREE;
+			break;
+	}
+	
+	return oldValue;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_WriteFatEntryFlushBuffer
+Flush the FAT buffer back to the disc
+-----------------------------------------------------------------*/
+bool FAT_WriteFatEntryFlushBuffer (void)
+{
+	// write the buffer disc
+	if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+	{
+		disc_WriteSector(fatBufferCurSector, fatBuffer);
+		return true;
+	} else {
+		return false;
+	}
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_FirstFreeCluster
+Internal function - gets the first available free cluster
+-----------------------------------------------------------------*/
+u32 FAT_FirstFreeCluster(void)
+{
+	// Start at first valid cluster
+	if (fatFirstFree < CLUSTER_FIRST)
+		fatFirstFree = CLUSTER_FIRST;
+
+	while ((FAT_NextCluster(fatFirstFree) != CLUSTER_FREE) && (fatFirstFree <= fatLastCluster))
+	{
+		fatFirstFree++;
+	}
+	if (fatFirstFree > fatLastCluster)
+	{
+		return CLUSTER_EOF;
+	}
+	return fatFirstFree;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_LinkFreeCluster
+Internal function - gets the first available free cluster, sets it
+to end of file, links the input cluster to it then returns the 
+cluster number
+-----------------------------------------------------------------*/
+u32 FAT_LinkFreeCluster(u32 cluster)
+{
+	u32 firstFree;
+	u32 curLink;
+
+	if (cluster > fatLastCluster)
+	{
+		return CLUSTER_FREE;
+	}
+
+	// Check if the cluster already has a link, and return it if so
+	curLink = FAT_NextCluster (cluster);
+	if ((curLink >= CLUSTER_FIRST) && (curLink < fatLastCluster))
+	{
+		return curLink;	// Return the current link - don't allocate a new one
+	}
+	
+	// Get a free cluster
+	firstFree = FAT_FirstFreeCluster();
+
+	// If couldn't get a free cluster then return
+	if (firstFree == CLUSTER_EOF)
+	{
+		return CLUSTER_FREE;
+	}
+
+	if ((cluster >= CLUSTER_FIRST) && (cluster < fatLastCluster))
+	{
+		// Update the linked from FAT entry
+		FAT_WriteFatEntry (cluster, firstFree);
+	}
+	// Create the linked to FAT entry
+	FAT_WriteFatEntry (firstFree, CLUSTER_EOF);
+
+	return firstFree;
+}
+#endif
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_ClearLinks
+Internal function - frees any cluster used by a file
+-----------------------------------------------------------------*/
+bool FAT_ClearLinks (u32 cluster)
+{
+	u32 nextCluster;
+	
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+		return false;
+
+	// Store next cluster before erasing the link
+	nextCluster = FAT_NextCluster (cluster);
+
+	// Erase the link
+	FAT_WriteFatEntry (cluster, CLUSTER_FREE);
+
+	// Move onto next cluster
+	cluster = nextCluster;
+
+	while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE))
+	{
+		cluster = FAT_ReadWriteFatEntryBuffered (cluster, CLUSTER_FREE);
+	} 
+
+	// Flush fat write buffer
+	FAT_WriteFatEntryFlushBuffer ();
+
+	return true;
+}
+#endif
+
+
+/*-----------------------------------------------------------------
+FAT_InitFiles
+Reads the FAT information from the CF card.
+You need to call this before reading any files.
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_InitFiles (void)
+{
+	int i;
+	int bootSector;
+	BOOT_SEC* bootSec;
+	
+	if (!disc_Init())
+	{
+		return (false);
+	}
+	
+	// Read first sector of CF card
+	if ( !disc_ReadSector(0, globalBuffer)) {
+		return false;
+	}
+
+	// Make sure it is a valid MBR or boot sector
+	if ( (globalBuffer[0x1FE] != 0x55) || (globalBuffer[0x1FF] != 0xAA)) {
+		return false;
+	}
+
+	// Check if there is a FAT string, which indicates this is a boot sector
+	if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T'))
+	{
+		bootSector = 0;
+	}
+	// Check for FAT32
+	else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T'))
+	{
+		bootSector = 0;
+	}
+	else	// This is an MBR
+	{
+		// Find first valid partition from MBR
+		// First check for an active partition
+		for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10);
+		// If it didn't find an active partition, search for any valid partition
+		if (i == 0x1FE) 
+			for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10);
+		
+		// Go to first valid partition
+		if ( i != 0x1FE)	// Make sure it found a partition
+		{
+			bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F);
+		} else {
+			bootSector = 0;	// No partition found, assume this is a MBR free disk
+		}
+	}
+
+	// Read in boot sector
+	bootSec = (BOOT_SEC*) globalBuffer;
+	if (!disc_ReadSector (bootSector,  bootSec)) {
+		return false;
+	}
+	
+	// Store required information about the file system
+	if (bootSec->sectorsPerFAT != 0)
+	{
+		filesysSecPerFAT = bootSec->sectorsPerFAT;
+	}
+	else
+	{
+		filesysSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32;
+	}
+	
+	if (bootSec->numSectorsSmall != 0)
+	{
+		filesysNumSec = bootSec->numSectorsSmall;
+	}
+	else
+	{
+		filesysNumSec = bootSec->numSectors;
+	}
+
+	filesysBytePerSec = BYTE_PER_READ;	// Sector size is redefined to be 512 bytes
+	filesysSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTE_PER_READ;
+	filesysBytePerClus = filesysBytePerSec * filesysSecPerClus;
+	filesysFAT = bootSector + bootSec->reservedSectors;
+
+	filesysRootDir = filesysFAT + (bootSec->numFATs * filesysSecPerFAT);
+	filesysData = filesysRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / filesysBytePerSec);
+
+	filesysTotalSize = (filesysNumSec - filesysData) * filesysBytePerSec;
+
+	// Store info about FAT
+	fatLastCluster = (filesysNumSec - filesysData) / bootSec->sectorsPerCluster;
+	fatFirstFree = CLUSTER_FIRST;
+	fatBufferCurSector = 0;
+	disc_ReadSector(fatBufferCurSector, fatBuffer);
+
+	if (fatLastCluster < 4085)
+	{
+		filesysType = FS_FAT12;	// FAT12 volume - unsupported
+	}
+	else if (fatLastCluster < 65525)
+	{
+		filesysType = FS_FAT16;	// FAT16 volume
+	}
+	else
+	{
+		filesysType = FS_FAT32;	// FAT32 volume
+	}
+
+	if (filesysType != FS_FAT32)
+	{
+		filesysRootDirClus = FAT16_ROOT_DIR_CLUSTER;
+	}
+	else	// Set up for the FAT32 way
+	{
+		filesysRootDirClus = bootSec->extBlock.fat32.rootClus;
+		// Check if FAT mirroring is enabled
+		if (!(bootSec->extBlock.fat32.extFlags & 0x80))
+		{
+			// Use the active FAT
+			filesysFAT = filesysFAT + ( filesysSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F));
+		}
+	}
+
+	// Set current directory to the root
+	curWorkDirCluster = filesysRootDirClus;
+	wrkDirCluster = filesysRootDirClus;
+	wrkDirSector = 0;
+	wrkDirOffset = 0;
+
+	// Set all files to free
+	for (i=0; i < MAX_FILES_OPEN; i++)
+	{
+		openFiles[i].inUse = false;
+	}
+
+	// No long filenames so far
+	lfnExists = false;
+	for (i = 0; i < MAX_FILENAME_LENGTH; i++)
+	{
+		lfnName[i] = '\0';
+	}
+
+	return (true);
+}
+
+/*-----------------------------------------------------------------
+FAT_FreeFiles
+Closes all open files then resets the CF card.
+Call this before exiting back to the GBAMP
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_FreeFiles (void)
+{
+	int i;
+
+	// Close all open files
+	for (i=0; i < MAX_FILES_OPEN; i++)
+	{
+		if (openFiles[i].inUse == true)
+		{
+			FAT_fclose(&openFiles[i]);
+		}
+	}
+
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+
+	// Clear card status
+	disc_ClearStatus();
+
+	// Return status of card
+	return disc_IsInserted();
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetDirEntry
+Return the file info structure of the next valid file entry
+u32 dirCluster: IN cluster of subdirectory table
+int entry: IN the desired file entry
+int origin IN: relative position of the entry
+DIR_ENT return OUT: desired dirEntry. First char will be FILE_FREE if 
+	the entry does not exist.
+-----------------------------------------------------------------*/
+DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin)
+{
+	DIR_ENT dir;
+	DIR_ENT_LFN lfn;
+	int firstSector = 0;
+	bool notFound = false;
+	bool found = false;
+	int maxSectors;
+	int lfnPos, aliasPos;
+	u8 lfnChkSum, chkSum;
+
+	int i;
+
+	dir.name[0] = FILE_FREE; // default to no file found
+	dir.attrib = 0x00;
+
+	// Check if fat has been initialised
+	if (filesysBytePerSec == 0)
+	{
+		return (dir);
+	}
+	
+	switch (origin) 
+	{
+	case SEEK_SET:
+		wrkDirCluster = dirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		break;
+	case SEEK_CUR:	// Don't change anything
+		break;
+	case SEEK_END:	// Find entry signifying end of directory
+		// Subtraction will never reach 0, so it keeps going 
+		// until reaches end of directory
+		wrkDirCluster = dirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		entry = -1;
+		break;
+	default:
+		return dir;
+	}
+
+	lfnChkSum = 0;
+	maxSectors = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus);
+
+	// Scan Dir for correct entry
+	firstSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster));
+	disc_ReadSector (firstSector + wrkDirSector, globalBuffer);
+	found = false;
+	notFound = false;
+	do {
+		wrkDirOffset++;
+		if (wrkDirOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			wrkDirOffset = 0;
+			wrkDirSector++;
+			if ((wrkDirSector == filesysSecPerClus) && (wrkDirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				wrkDirSector = 0;
+				wrkDirCluster = FAT_NextCluster(wrkDirCluster);
+				if (wrkDirCluster == CLUSTER_EOF)
+				{
+					notFound = true;
+				}
+				firstSector = FAT_ClustToSect(wrkDirCluster);		
+			}
+			else if ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER) && (wrkDirSector == (filesysData - filesysRootDir)))
+			{
+				notFound = true;	// Got to end of root dir
+			}
+			disc_ReadSector (firstSector + wrkDirSector, globalBuffer);
+		}
+		dir = ((DIR_ENT*) globalBuffer)[wrkDirOffset];
+		if ((dir.name[0] != FILE_FREE) && (dir.name[0] > 0x20) && ((dir.attrib & ATTRIB_VOL) != ATTRIB_VOL))
+		{
+			entry--;
+			if (lfnExists)
+			{
+				// Calculate file checksum
+				chkSum = 0;
+				for (aliasPos=0; aliasPos < 11; aliasPos++)
+				{
+					// NOTE: The operation is an unsigned char rotate right
+					chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + (aliasPos < 8 ? dir.name[aliasPos] : dir.ext[aliasPos - 8]);
+				}
+				if (chkSum != lfnChkSum)
+				{
+					lfnExists = false;
+					lfnName[0] = '\0';
+				}
+			}
+			if (entry == 0) 
+			{
+				if (!lfnExists)
+				{
+					FAT_GetFilename (dir, lfnName);
+				}
+				found = true;
+			}
+		}
+		else if (dir.name[0] == FILE_LAST)
+		{
+			if (origin == SEEK_END)
+			{
+				found = true;
+			}
+			else
+			{
+				notFound = true;
+			}
+		}
+		else if (dir.attrib == ATTRIB_LFN)
+		{
+			lfn = ((DIR_ENT_LFN*) globalBuffer)[wrkDirOffset];
+			if (lfn.ordinal & LFN_DEL)
+			{
+				lfnExists = false;
+			}
+			else if (lfn.ordinal & LFN_END)	// Last part of LFN, make sure it isn't deleted (Thanks MoonLight)
+			{
+				lfnExists = true;
+				lfnName[(lfn.ordinal & ~LFN_END) * 13] = '\0';	// Set end of lfn to null character
+				lfnChkSum = lfn.checkSum;
+			}
+			if (lfnChkSum != lfn.checkSum)
+			{
+				lfnExists = false;
+			}
+			if (lfnExists)
+			{
+				lfnPos = ((lfn.ordinal & ~LFN_END) - 1) * 13;
+				for (i = 0; i < 13; i++) {
+					lfnName[lfnPos + i] = ((u8*)&lfn)[(int)(lfn_offset_table[i])] /* | ((u8*)&lfn)[(int)(lfn_offset_table[i]) + 1]  include this for unicode support*/;
+				}
+			}
+		}
+	} while (!found && !notFound);
+	
+	// If no file is found, return FILE_FREE
+	if (notFound)
+	{
+		dir.name[0] = FILE_FREE;
+	}
+
+	return (dir);
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetLongFilename
+Get the long name of the last file or directory retrived with 
+	GetDirEntry. Also works for FindFirstFile and FindNextFile.
+	If a long name doesn't exist, it returns the short name
+	instead.
+char* filename: OUT will be filled with the filename, should be at
+	least 256 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetLongFilename (char* filename)
+{
+	if (filename == NULL)
+		return false;
+
+	strncpy (filename, lfnName, MAX_FILENAME_LENGTH - 1);
+	filename[MAX_FILENAME_LENGTH - 1] = '\0';
+	
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetFilename
+Get the alias (short name) of the file or directory stored in 
+	dirEntry
+DIR_ENT dirEntry: IN a valid directory table entry
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetFilename (DIR_ENT dirEntry, char* alias)
+{
+	int i=0;
+	int j=0;
+
+	alias[0] = '\0';
+	if (dirEntry.name[0] != FILE_FREE)
+	{
+		if (dirEntry.name[0] == '.')
+		{
+			alias[0] = '.';
+			if (dirEntry.name[1] == '.')
+			{
+				alias[1] = '.';
+				alias[2] = '\0';
+			}
+			else
+			{
+				alias[1] = '\0';
+			}
+		}
+		else
+		{		
+			// Copy the filename from the dirEntry to the string
+			for (i = 0; (i < 8) && (dirEntry.name[i] != ' '); i++)
+			{
+				alias[i] = dirEntry.name[i];
+			}
+			// Copy the extension from the dirEntry to the string
+			if (dirEntry.ext[0] != ' ')
+			{
+				alias[i++] = '.';
+				for ( j = 0; (j < 3) && (dirEntry.ext[j] != ' '); j++)
+				{
+					alias[i++] = dirEntry.ext[j];
+				}
+			}
+			alias[i] = '\0';
+		}
+	}
+
+	return (alias[0] != '\0');
+}
+
+/*-----------------------------------------------------------------
+FAT_GetAlias
+Get the alias (short name) of the last file or directory entry read
+	using GetDirEntry. Works for FindFirstFile and FindNextFile
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetAlias (char* alias)
+{
+	if (alias == NULL)
+	{
+		return false;
+	}
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_GetFilename (((DIR_ENT*)globalBuffer)[wrkDirOffset], alias);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSize
+Get the file size of the last file found or openned.
+This idea is based on a modification by MoonLight
+u32 return OUT: the file size
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSize (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].fileSize;
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileCluster
+Get the first cluster of the last file found or openned.
+u32 return OUT: the file start cluster
+-----------------------------------------------------------------*/
+u32 FAT_GetFileCluster (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	(((DIR_ENT*)globalBuffer)[wrkDirOffset].startCluster) | (((DIR_ENT*)globalBuffer)[wrkDirOffset].startClusterHigh << 16);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileAttributes
+Get the attributes of the last file found or openned.
+u8 return OUT: the file's attributes
+-----------------------------------------------------------------*/
+u8 FAT_GetFileAttributes (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_SetFileAttributes
+Set the attributes of a file.
+const char* filename IN: The name and path of the file to modify
+u8 attributes IN: The attribute values to assign
+u8 mask IN: Detemines which attributes are changed
+u8 return OUT: the file's new attributes
+-----------------------------------------------------------------*/
+u8 FAT_SetFileAttributes (const char* filename, u8 attributes, u8 mask)
+{
+	// Get the file
+	if (!FAT_FileExists(filename)) {
+		return 0xff;
+	}
+
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+
+	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib = (((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib & ~(mask & 0x27)) | (attributes & 0x27);	// 0x27 is he settable attributes
+	
+	disc_WriteSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib;
+}
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+time_t FAT_FileTimeToCTime (u16 fileTime, u16 fileDate)
+{
+	struct tm timeInfo;
+	
+	timeInfo.tm_year = (fileDate >> 9) + 80;		// years since midnight January 1970
+	timeInfo.tm_mon = ((fileDate >> 5) & 0xf) - 1;	// Months since january
+	timeInfo.tm_mday = fileDate & 0x1f;				// Day of the month
+
+	timeInfo.tm_hour = fileTime >> 11;				// hours past midnight
+	timeInfo.tm_min = (fileTime >> 5) & 0x3f;		// minutes past the hour
+	timeInfo.tm_sec = (fileTime & 0x1f) * 2;		// seconds past the minute
+
+	return mktime(&timeInfo);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileCreationTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileCreationTime (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].cTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].cDate);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileLastWriteTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileLastWriteTime (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].mTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].mDate);
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_DirEntFromPath
+Finds the directory entry for a file or directory from a path
+Path separator is a forward slash /
+const char* path: IN null terminated string of path.
+DIR_ENT return OUT: dirEntry of found file. First char will be FILE_FREE
+	if the file was not found
+-----------------------------------------------------------------*/
+DIR_ENT FAT_DirEntFromPath (const char* path)
+{
+	int pathPos;
+	char name[MAX_FILENAME_LENGTH];
+	char alias[13];
+	int namePos;
+	bool found, notFound;
+	DIR_ENT dirEntry;
+	u32 dirCluster;
+	bool flagLFN, dotSeen;
+	
+	// Start at beginning of path
+	pathPos = 0;
+	
+	if (path[pathPos] == '/') 
+	{
+		dirCluster = filesysRootDirClus;	// Start at root directory
+	}
+	else
+	{
+		dirCluster = curWorkDirCluster;	// Start at current working dir
+	}
+	
+	// Eat any slash /
+	while ((path[pathPos] == '/') && (path[pathPos] != '\0'))
+	{
+		pathPos++;
+	}
+	
+	// Search until can't continue
+	found = false;
+	notFound = false;
+	while (!notFound && !found)
+	{
+		flagLFN = false;
+		// Copy name from path
+		namePos = 0;
+		if ((path[pathPos] == '.') && ((path[pathPos + 1] == '\0') || (path[pathPos + 1] == '/'))) {
+			// Dot entry
+			name[namePos++] = '.';
+			pathPos++;
+		} else if ((path[pathPos] == '.') && (path[pathPos + 1] == '.') && ((path[pathPos + 2] == '\0') || (path[pathPos + 2] == '/'))){
+			// Double dot entry
+			name[namePos++] = '.';
+			pathPos++;
+			name[namePos++] = '.';
+			pathPos++;
+		} else {
+			// Copy name from path
+			if (path[pathPos] == '.') {
+				flagLFN = true;
+			}
+			dotSeen = false;
+			while ((namePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0') && (path[pathPos] != '/'))
+			{
+				name[namePos] = ucase(path[pathPos]);
+				if ((name[namePos] <= ' ') || ((name[namePos] >= ':') && (name[namePos] <= '?'))) // Invalid character
+				{
+					flagLFN = true;
+				}
+				if (name[namePos] == '.') {
+					if (!dotSeen) {
+						dotSeen = true;
+					} else {
+						flagLFN = true;
+					}
+				}
+				namePos++;
+				pathPos++;
+			}
+			// Check if a long filename was specified
+			if (namePos > 12)
+			{
+				flagLFN = true;
+			}
+		}
+		
+		// Add end of string char
+		name[namePos] = '\0';
+
+		// Move through path to correct place
+		while ((path[pathPos] != '/') && (path[pathPos] != '\0'))
+			pathPos++;
+		// Eat any slash /
+		while ((path[pathPos] == '/') && (path[pathPos] != '\0'))
+		{
+			pathPos++;
+		}
+
+		// Search current Dir for correct entry
+		dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_SET);
+		while ( !found && !notFound)
+		{
+			// Match filename
+			found = true;
+			for (namePos = 0; (namePos < MAX_FILENAME_LENGTH) && found && (name[namePos] != '\0') && (lfnName[namePos] != '\0'); namePos++)
+			{
+				if (name[namePos] != ucase(lfnName[namePos]))
+				{
+					found = false;
+				}
+			}
+			if ((name[namePos] == '\0') != (lfnName[namePos] == '\0'))
+			{
+				found = false;
+			}
+
+			// Check against alias as well.
+			if (!found)
+			{
+				FAT_GetFilename(dirEntry, alias);
+				found = true;
+				for (namePos = 0; (namePos < 13) && found && (name[namePos] != '\0') && (alias[namePos] != '\0'); namePos++)
+				{
+					if (name[namePos] != ucase(alias[namePos]))
+					{
+						found = false;
+					}
+				}
+				if ((name[namePos] == '\0') != (alias[namePos] == '\0'))
+				{
+					found = false;
+				}
+			}
+
+			if (dirEntry.name[0] == FILE_FREE)
+				// Couldn't find specified file
+			{
+				found = false;
+				notFound = true;
+			}
+			if (!found && !notFound)
+			{
+				dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_CUR);
+			}
+		}
+		
+		if (found && ((dirEntry.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (path[pathPos] != '\0'))
+			// It has found a directory from within the path that needs to be followed
+		{
+			found = false;
+			dirCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+		}
+	}
+	
+	if (notFound)
+	{
+		dirEntry.name[0] = FILE_FREE;
+		dirEntry.attrib = 0x00;
+	}
+
+	return (dirEntry);
+}
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_AddDirEntry
+Creates a new dir entry for a file
+Path separator is a forward slash /
+const char* path: IN null terminated string of path to file.
+DIR_ENT newDirEntry IN: The directory entry to use.
+int file IN: The file being added (optional, use -1 if not used)
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry)
+{
+	char filename[MAX_FILENAME_LENGTH];
+	int filePos, pathPos, aliasPos;
+	char tempChar;
+	bool flagLFN, dotSeen;
+	char fileAlias[13] = {0};
+	int tailNum;
+	
+	unsigned char chkSum = 0;
+	
+	u32 oldWorkDirCluster;
+	
+	DIR_ENT* dirEntries = (DIR_ENT*)globalBuffer;
+	u32 dirCluster;
+	int secOffset;
+	int entryOffset;
+	int maxSectors;
+	u32 firstSector;
+
+	DIR_ENT_LFN lfnEntry;
+	int lfnPos = 0;
+
+	int dirEntryLength = 0;
+	int dirEntryRemain = 0;
+	u32 tempDirCluster;
+	int tempSecOffset;
+	int tempEntryOffset;
+	bool dirEndFlag = false;
+
+	int i;
+
+	// Store current working directory
+	oldWorkDirCluster = curWorkDirCluster;
+
+	// Find filename within path and change to correct directory
+	if (path[0] == '/')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+	}
+	
+	pathPos = 0;
+	filePos = 0;
+	flagLFN = false;
+
+	while (path[pathPos + filePos] != '\0')
+	{
+		if (path[pathPos + filePos] == '/')
+		{
+			filename[filePos] = '\0';
+			if (FAT_chdir(filename) == false) 
+			{
+				curWorkDirCluster = oldWorkDirCluster;
+				return false; // Couldn't change directory
+			}
+			pathPos += filePos + 1;
+			filePos = 0;
+		}
+		filename[filePos] = path[pathPos + filePos];
+		filePos++;
+	}
+	
+	// Skip over last slashes
+	while (path[pathPos] == '/')
+		pathPos++;
+	
+	// Check if the filename has a leading "."
+	// If so, it is an LFN
+	if (path[pathPos] == '.') {
+		flagLFN = true;
+	}
+	
+	// Copy name from path
+	filePos = 0;
+	dotSeen = false;
+
+	while ((filePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0'))
+	{
+		filename[filePos] = path[pathPos];
+		if ((filename[filePos] <= ' ') || ((filename[filePos] >= ':') && (filename[filePos] <= '?'))) // Invalid character
+		{
+			flagLFN = true;
+		}
+		if (filename[filePos] == '.') {
+			if (!dotSeen) {
+				dotSeen = true;
+			} else {
+				flagLFN = true;
+			}
+		}
+		filePos++;
+		pathPos++;
+		if ((filePos > 8) && !dotSeen) {
+			flagLFN = true;
+		}
+	}
+	
+	if (filePos == 0)	// No filename
+	{
+		return false;
+	}
+	
+	// Check if a long filename was specified
+	if (filePos > 12)
+	{
+		flagLFN = true;
+	}
+
+	// Check if extension is > 3 characters long
+	if (!flagLFN && (strrchr (filename, '.') != NULL) && (strlen(strrchr(filename, '.')) > 4)) {
+		flagLFN = true;
+	}
+	
+	lfnPos = (filePos - 1) / 13;
+
+	// Add end of string char
+	filename[filePos++] = '\0';
+	// Clear remaining chars
+	while (filePos < MAX_FILENAME_LENGTH)
+		filename[filePos++] = 0x01;	// Set for LFN compatibility
+	
+	
+	if (flagLFN)
+	{
+		// Generate short filename - always a 2 digit number for tail
+		// Get first 5 chars of alias from LFN
+		aliasPos = 0;
+		filePos = 0;
+		if (filename[filePos] == '.') {
+			filePos++;
+		}
+		for ( ; (aliasPos < 5) && (filename[filePos] != '\0') && (filename[filePos] != '.') ; filePos++)
+		{
+			tempChar = ucase(filename[filePos]);
+			if (((tempChar > ' ' && tempChar < ':') || tempChar > '?') && tempChar != '.')
+				fileAlias[aliasPos++] = tempChar;
+		}
+		// Pad Alias with underscores
+		while (aliasPos < 5)
+			fileAlias[aliasPos++] = '_';
+		
+		fileAlias[5] = '~';
+		fileAlias[8] = '.';
+		fileAlias[9] = ' ';
+		fileAlias[10] = ' ';
+		fileAlias[11] = ' ';
+		if (strchr (filename, '.') != NULL) {
+			while(filename[filePos] != '\0')
+			{
+				filePos++;
+				if (filename[filePos] == '.')
+				{
+					pathPos = filePos;
+				}
+			}
+			filePos = pathPos + 1;	//pathPos is used as a temporary variable
+			// Copy first 3 characters of extension
+			for (aliasPos = 9; (aliasPos < 12) && (filename[filePos] != '\0'); filePos++)
+			{
+				tempChar = ucase(filename[filePos]);
+				if ((tempChar > ' ' && tempChar < ':') || tempChar > '?')
+					fileAlias[aliasPos++] = tempChar;
+			}
+		} else {
+			aliasPos = 9;
+		}
+		
+		// Pad Alias extension with spaces
+		while (aliasPos < 12)
+			fileAlias[aliasPos++] = ' ';
+		
+		fileAlias[12] = '\0';
+		
+		
+		// Get a valid tail number
+		tailNum = 0;
+		do {
+			tailNum++;
+			fileAlias[6] = 0x30 + ((tailNum / 10) % 10);	// 10's digit
+			fileAlias[7] = 0x30 + (tailNum % 10);	// 1's digit
+		} while ((FAT_DirEntFromPath(fileAlias).name[0] != FILE_FREE) && (tailNum < 100));
+		
+		if (tailNum < 100)	// Found an alias not being used
+		{
+			// Calculate file checksum
+			chkSum = 0;
+			for (aliasPos=0; aliasPos < 12; aliasPos++)
+			{
+				// Skip '.'
+				if (fileAlias[aliasPos] == '.')
+					aliasPos++;
+				// NOTE: The operation is an unsigned char rotate right
+				chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + fileAlias[aliasPos];
+			}
+		}
+		else	// Couldn't find a valid alias
+		{
+			return false;
+		}
+		
+		dirEntryLength = lfnPos + 2;
+	}
+	else	// Its not a long file name
+	{
+		// Just copy alias straight from filename
+		for (aliasPos = 0; aliasPos < 13; aliasPos++)
+		{
+			tempChar = ucase(filename[aliasPos]);
+			if ((tempChar > ' ' && tempChar < ':') || tempChar > '?')
+				fileAlias[aliasPos] = tempChar;
+		}
+		fileAlias[12] = '\0';
+
+		lfnPos = -1;
+
+		dirEntryLength = 1;
+	}
+	
+	// Change dirEntry name to match alias
+	for (aliasPos = 0; ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0') && (aliasPos < 8)); aliasPos++)
+	{
+		newDirEntry.name[aliasPos] = fileAlias[aliasPos];
+	}
+	while (aliasPos < 8)
+	{
+		newDirEntry.name[aliasPos++] = ' ';
+	}
+	aliasPos = 0;
+	while ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0'))
+		aliasPos++;
+	filePos = 0;
+	while (( filePos < 3 ) && (fileAlias[aliasPos] != '\0'))
+	{
+		tempChar = fileAlias[aliasPos++];
+		if ((tempChar > ' ' && tempChar < ':' && tempChar!='.') || tempChar > '?')
+			newDirEntry.ext[filePos++] = tempChar;
+	}
+	while (filePos < 3)
+	{
+		newDirEntry.ext[filePos++] = ' ';
+	}
+
+	// Scan Dir for free entry
+	dirCluster = curWorkDirCluster;
+	secOffset = 0;
+	entryOffset = 0;
+	maxSectors = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus);
+	firstSector = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(dirCluster));
+	disc_ReadSector (firstSector + secOffset, dirEntries);
+	
+	dirEntryRemain = dirEntryLength;
+	tempDirCluster = dirCluster;
+	tempSecOffset = secOffset;
+	tempEntryOffset = entryOffset;
+		
+	// Search for a large enough space to fit in new directory entry
+	while ((dirEntries[entryOffset].name[0] != FILE_LAST) && (dirEntryRemain > 0))
+	{
+
+		entryOffset++;
+
+		if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			entryOffset = 0;
+			secOffset++;
+			if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				secOffset = 0;
+				if (FAT_NextCluster(dirCluster) == CLUSTER_EOF)
+				{
+					dirCluster = FAT_LinkFreeCluster(dirCluster);
+					dirEntries[0].name[0] = FILE_LAST;
+				}
+				else
+				{
+					dirCluster = FAT_NextCluster(dirCluster);
+				}
+				firstSector = FAT_ClustToSect(dirCluster);		
+			}
+			else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir)))
+			{
+				return false;	// Got to end of root dir - can't fit in more files
+			}
+			disc_ReadSector (firstSector + secOffset, dirEntries);
+		}
+
+		if ((dirEntries[entryOffset].name[0] == FILE_FREE) || (dirEntries[entryOffset].name[0] == FILE_LAST) )
+		{
+			dirEntryRemain--;
+		} else {
+			dirEntryRemain = dirEntryLength;
+			tempDirCluster = dirCluster;
+			tempSecOffset = secOffset;
+			tempEntryOffset = entryOffset;
+		}
+	}
+
+	// Modifying the last directory is a special case - have to erase following entries
+	if (dirEntries[entryOffset].name[0] == FILE_LAST) 
+	{
+		dirEndFlag = true;
+	}
+
+	// Recall last used entry
+	dirCluster = tempDirCluster;
+	secOffset = tempSecOffset;
+	entryOffset = tempEntryOffset;
+	dirEntryRemain = dirEntryLength;
+
+	// Re-read in first sector that will be written to
+	if (dirEndFlag && (entryOffset == 0))	{
+		memset (dirEntries, FILE_LAST, BYTE_PER_READ);
+	} else {
+		disc_ReadSector (firstSector + secOffset, dirEntries);
+	}
+
+	// Add new directory entry
+	while (dirEntryRemain > 0)	
+	{
+		// Move to next entry, first pass advances from last used entry
+		entryOffset++;
+		if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			// Write out the current sector if we need to
+			entryOffset = 0;
+			if (dirEntryRemain < dirEntryLength) // Don't write out sector on first pass
+			{
+				disc_WriteSector (firstSector + secOffset, dirEntries);
+			}
+			secOffset++;
+			if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				secOffset = 0;
+				if (FAT_NextCluster(dirCluster) == CLUSTER_EOF)
+				{
+					dirCluster = FAT_LinkFreeCluster(dirCluster);
+					dirEntries[0].name[0] = FILE_LAST;
+				}
+				else
+				{
+					dirCluster = FAT_NextCluster(dirCluster);
+				}
+				firstSector = FAT_ClustToSect(dirCluster);		
+			}
+			else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir)))
+			{
+				return false;	// Got to end of root dir - can't fit in more files
+			}
+			if (dirEndFlag)
+			{
+				memset (dirEntries, FILE_LAST, BYTE_PER_READ);
+			} else {
+				disc_ReadSector (firstSector + secOffset, dirEntries);
+			}
+		}
+
+		// Generate LFN entries
+		if (lfnPos >= 0)
+		{
+			lfnEntry.ordinal = (lfnPos + 1) | (dirEntryRemain == dirEntryLength ? LFN_END : 0);
+			for (i = 0; i < 13; i++) {
+				if (filename [lfnPos * 13 + i] == 0x01) {
+					((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = 0xff;
+					((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0xff;
+				} else {
+					((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = filename [lfnPos * 13 + i];
+					((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0x00;
+				}
+			}
+
+			lfnEntry.checkSum = chkSum;
+			lfnEntry.flag = ATTRIB_LFN;
+			lfnEntry.reserved1 = 0;
+			lfnEntry.reserved2 = 0;
+			
+			*((DIR_ENT_LFN*)&dirEntries[entryOffset]) = lfnEntry;
+			lfnPos --;
+			lfnEntry.ordinal = 0;
+		}	// end writing long filename entries
+		else
+		{
+			dirEntries[entryOffset] = newDirEntry;
+			if (dirEndFlag && (entryOffset < (BYTE_PER_READ / sizeof (DIR_ENT))) )
+				dirEntries[entryOffset+1].name[0] = FILE_LAST;
+		}
+
+		dirEntryRemain--;
+	}
+	
+	// Write directory back to disk
+	disc_WriteSector (firstSector + secOffset, dirEntries);
+
+	// Change back to Working DIR
+	curWorkDirCluster = oldWorkDirCluster;
+
+	return true;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_FindNextFile
+Gets the name of the next directory entry
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFile(char* filename)
+{
+	// Get the next directory entry
+	DIR_ENT file;
+	file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_CUR);
+
+	if (file.name[0] == FILE_FREE)
+	{
+		return FT_NONE;	// Did not find a file
+	}
+
+	// Get the filename
+	if (filename != NULL)
+		FAT_GetFilename (file, filename);
+
+	if ((file.attrib & ATTRIB_DIR) != 0)
+	{
+		return FT_DIR;	// Found a directory
+	}
+	else
+	{
+		return FT_FILE;	// Found a file
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFile
+Gets the name of the first directory entry and resets the count
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFile(char* filename)
+{
+	// Get the first directory entry
+	DIR_ENT file;
+	file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_SET);
+	
+	if (file.name[0] == FILE_FREE)
+	{
+		return FT_NONE;	// Did not find a file
+	}
+
+	// Get the filename
+	if (filename != NULL)
+		FAT_GetFilename (file, filename);
+
+	if ((file.attrib & ATTRIB_DIR) != 0)
+	{
+		return FT_DIR;	// Found a directory
+	}
+	else
+	{
+		return FT_FILE;	// Found a file
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFileLFN
+Gets the long file name of the first directory entry and resets
+	the count (can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFileLFN(char* lfn)
+{
+	FILE_TYPE type;
+	type = FAT_FindFirstFile(NULL);
+	FAT_GetLongFilename (lfn);
+	return type;
+}
+
+/*-----------------------------------------------------------------
+FAT_FindNextFileLFN
+Gets the long file name of the next directory entry
+	(can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFileLFN(char* lfn)
+{
+	FILE_TYPE type;
+	type = FAT_FindNextFile(NULL);
+	FAT_GetLongFilename (lfn);
+	return type;
+}
+
+
+/*-----------------------------------------------------------------
+FAT_FileExists
+Returns the type of file 
+char* filename: IN filename of the file to look for
+FILE_TYPE return: OUT returns FT_NONE if there is now file with 
+	that name, FT_FILE if it is a file and FT_DIR if it is a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FileExists(const char* filename)
+{
+    DIR_ENT dirEntry; 
+    // Get the dirEntry for the path specified 
+    dirEntry = FAT_DirEntFromPath (filename); 
+
+    if (dirEntry.name[0] == FILE_FREE) 
+    { 
+        return FT_NONE; 
+    } 
+    else if (dirEntry.attrib & ATTRIB_DIR) 
+    { 
+        return FT_DIR; 
+    } 
+    else 
+    { 
+         return FT_FILE; 
+    } 
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemType
+FS_TYPE return: OUT returns the current file system type
+-----------------------------------------------------------------*/
+FS_TYPE FAT_GetFileSystemType (void)
+{
+	return filesysType;
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemTotalSize
+u32 return: OUT returns the total disk space (used + free)
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSystemTotalSize (void)
+{
+	return filesysTotalSize;
+}
+
+
+
+/*-----------------------------------------------------------------
+FAT_chdir
+Changes the current working directory
+const char* path: IN null terminated string of directory separated by 
+	forward slashes, / is root
+bool return: OUT returns true if successful
+-----------------------------------------------------------------*/
+bool FAT_chdir (const char* path)
+{
+	DIR_ENT dir;
+	if (path[0] == '/' && path[1] == '\0')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+		return true;
+	}
+	if (path[0] == '\0')	// Return true if changing relative to nothing
+	{
+		return true;
+	}
+	
+	dir = FAT_DirEntFromPath (path);
+
+	if (((dir.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (dir.name[0] != FILE_FREE))
+	{
+		// Change directory
+		curWorkDirCluster = dir.startCluster | (dir.startClusterHigh << 16);
+
+		// Move to correct cluster for root directory
+		if (curWorkDirCluster == FAT16_ROOT_DIR_CLUSTER)
+		{
+			curWorkDirCluster = filesysRootDirClus;
+		}
+
+		// Reset file position in directory
+		wrkDirCluster = curWorkDirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		return true;
+	}
+	else
+	{ 
+		// Couldn't change directory - wrong path specified
+		return false;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_fopen(filename, mode)
+Opens a file
+const char* path: IN null terminated string of filename and path 
+	separated by forward slashes, / is root
+const char* mode: IN mode to open file in
+	Supported modes: "r", "r+", "w", "w+", "a", "a+", don't use
+	"b" or "t" in any mode, as all files are openned in binary mode
+FAT_FILE* return: OUT handle to open file, returns NULL if the file 
+	couldn't be openned
+-----------------------------------------------------------------*/
+FAT_FILE* FAT_fopen(const char* path, const char* mode)
+{
+	int fileNum;
+	FAT_FILE* file;
+	DIR_ENT dirEntry;
+#ifdef CAN_WRITE_TO_DISC
+	u32 startCluster;
+	int clusCount;
+#endif
+
+	char* pchTemp;
+	// Check that a valid mode was specified
+	pchTemp = strpbrk ( mode, "rRwWaA" );
+	if (pchTemp == NULL)
+	{
+		return NULL;
+	}
+	if (strpbrk ( pchTemp+1, "rRwWaA" ) != NULL)
+	{
+		return NULL;
+	}
+		
+	// Get the dirEntry for the path specified
+	dirEntry = FAT_DirEntFromPath (path);
+	
+	// Check that it is not a directory
+	if (dirEntry.attrib & ATTRIB_DIR)
+	{
+		return NULL;
+	}
+
+#ifdef CAN_WRITE_TO_DISC
+	// Check that it is not a read only file being openned in a writing mode
+	if ( (strpbrk(mode, "wWaA+") != NULL) && (dirEntry.attrib & ATTRIB_RO))
+	{
+		return NULL;
+	}
+#else
+	if ( (strpbrk(mode, "wWaA+") != NULL))
+	{
+		return NULL;
+	}
+#endif
+
+	// Find a free file buffer
+	for (fileNum = 0; (fileNum < MAX_FILES_OPEN) && (openFiles[fileNum].inUse == true); fileNum++);
+	
+	if (fileNum == MAX_FILES_OPEN) // No free files
+	{
+		return NULL;
+	}
+
+	file = &openFiles[fileNum];
+	// Remember where directory entry was
+	file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+	file->dirEntOffset = wrkDirOffset;
+
+	if ( strpbrk(mode, "rR") != NULL )  //(ucase(mode[0]) == 'R')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// File must exist
+		{
+			return NULL;
+		}
+		
+		file->read = true;
+#ifdef CAN_WRITE_TO_DISC
+		file->write = ( strchr(mode, '+') != NULL ); //(mode[1] == '+');
+#else
+		file->write = false;
+#endif
+		file->append = false;
+		
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+	
+#ifdef CAN_WRITE_TO_DISC
+		// Check if file is openned for random. If it is, and currently has no cluster, one must be 
+		// assigned to it.
+		if (file->write && file->firstCluster == CLUSTER_FREE)
+		{
+			file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+			if (file->firstCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+			{
+				return NULL;
+			}
+
+			// Store cluster position into the directory entry
+			dirEntry.startCluster = (file->firstCluster & 0xFFFF);
+			dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF);
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+			((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+		}
+#endif
+			
+		file->length = dirEntry.fileSize;
+		file->curPos = 0;
+		file->curClus = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+		file->curSect = 0;
+		file->curByte = 0;
+
+		// Not appending
+		file->appByte = 0;
+		file->appClus = 0;
+		file->appSect = 0;
+	
+		disc_ReadSector( FAT_ClustToSect( file->curClus), file->readBuffer);
+		file->inUse = true;	// We're using this file now
+
+		return file;
+	}	// mode "r"
+
+#ifdef CAN_WRITE_TO_DISC
+	if ( strpbrk(mode, "wW") != NULL ) // (ucase(mode[0]) == 'W')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// Create file if it doesn't exist
+		{
+			dirEntry.attrib = ATTRIB_ARCH;
+			dirEntry.reserved = 0;
+			
+			// Time and date set to system time and date
+			dirEntry.cTime_ms = 0;
+			dirEntry.cTime = getRTCtoFileTime();
+			dirEntry.cDate = getRTCtoFileDate();
+			dirEntry.aDate = getRTCtoFileDate();
+			dirEntry.mTime = getRTCtoFileTime();
+			dirEntry.mDate = getRTCtoFileDate();
+		}
+		else	// Already a file entry 
+		{
+			// Free any clusters used
+			FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16));
+		}
+		
+		// Get a cluster to use
+		startCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+		if (startCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+		{
+			return NULL;
+		}
+
+		// Store cluster position into the directory entry
+		dirEntry.startCluster = (startCluster & 0xFFFF);
+		dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF);
+
+		// The file has no data in it - its over written so should be empty
+		dirEntry.fileSize = 0;
+
+		if (dirEntry.name[0] == FILE_FREE)	// No file
+		{
+			// Have to create a new entry
+			if(!FAT_AddDirEntry (path, dirEntry))
+			{
+				return NULL;
+			}
+			// Get the newly created dirEntry
+			dirEntry = FAT_DirEntFromPath (path);
+
+			// Remember where directory entry was
+			file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+			file->dirEntOffset = wrkDirOffset;
+		}
+		else	// Already a file
+		{
+			// Just modify the old entry
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+			((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+		}
+		
+
+		// Now that file is created, open it
+		file->read = ( strchr(mode, '+') != NULL ); //(mode[1] == '+');
+		file->write = true;
+		file->append = false;
+		
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = startCluster;
+		file->length = 0;	// Should always have 0 bytes if openning in "w" mode
+		file->curPos = 0;
+		file->curClus = startCluster;
+		file->curSect = 0;
+		file->curByte = 0;
+
+		// Not appending
+		file->appByte = 0;
+		file->appClus = 0;
+		file->appSect = 0;
+		
+		// Empty file, so empty read buffer
+		memset (file->readBuffer, 0, BYTE_PER_READ);
+		file->inUse = true;	// We're using this file now
+
+		return file;
+	}
+
+	if ( strpbrk(mode, "aA") != NULL ) // (ucase(mode[0]) == 'A')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// Create file if it doesn't exist
+		{
+			dirEntry.attrib = ATTRIB_ARCH;
+			dirEntry.reserved = 0;
+			
+			// Time and date set to system time and date
+			dirEntry.cTime_ms = 0;
+			dirEntry.cTime = getRTCtoFileTime();
+			dirEntry.cDate = getRTCtoFileDate();
+			dirEntry.aDate = getRTCtoFileDate();
+			dirEntry.mTime = getRTCtoFileTime();
+			dirEntry.mDate = getRTCtoFileDate();
+
+			// The file has no data in it
+			dirEntry.fileSize = 0;
+
+			// Get a cluster to use
+			startCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+			if (startCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+			{
+				return NULL;
+			}
+			dirEntry.startCluster = (startCluster & 0xFFFF);
+			dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF);
+			
+			if(!FAT_AddDirEntry (path, dirEntry))
+				return NULL;
+			
+			// Get the newly created dirEntry
+			dirEntry = FAT_DirEntFromPath (path);
+			
+			// Store append cluster
+			file->appClus = startCluster;
+
+			// Remember where directory entry was
+			file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+			file->dirEntOffset = wrkDirOffset;
+		}
+		else	// File already exists - reuse the old directory entry
+		{
+			startCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+			// If it currently has no cluster, one must be assigned to it.
+			if (startCluster == CLUSTER_FREE)
+			{
+				file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+				if (file->firstCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+				{
+					return NULL;
+				}
+				
+				// Store cluster position into the directory entry
+				dirEntry.startCluster = (file->firstCluster & 0xFFFF);
+				dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF);
+				disc_ReadSector (file->dirEntSector, globalBuffer);
+				((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+				disc_WriteSector (file->dirEntSector, globalBuffer);
+
+				// Store append cluster
+				file->appClus = startCluster;
+		
+			} else {
+
+				// Follow cluster list until last one is found
+				clusCount = dirEntry.fileSize / filesysBytePerClus;
+				file->appClus = startCluster;
+				while ((clusCount--) && (FAT_NextCluster (file->appClus) != CLUSTER_FREE) && (FAT_NextCluster (file->appClus) != CLUSTER_EOF))
+				{
+					file->appClus = FAT_NextCluster (file->appClus);
+				}
+				if (clusCount >= 0) // Check if ran out of clusters
+				{
+					// Set flag to allocate new cluster when needed
+					file->appSect = filesysSecPerClus;
+					file->appByte = 0;
+				}
+			}
+		}
+
+		// Now that file is created, open it
+		file->read = ( strchr(mode, '+') != NULL );
+		file->write = false;
+		file->append = true;
+		
+		// Calculate the sector and byte of the current position,
+		// and store them
+		file->appSect = (dirEntry.fileSize % filesysBytePerClus) / BYTE_PER_READ;
+		file->appByte = dirEntry.fileSize % BYTE_PER_READ;
+
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = startCluster;
+		file->length = dirEntry.fileSize;
+		file->curPos = dirEntry.fileSize;
+		file->curClus = file->appClus;
+		file->curSect = file->appSect;
+		file->curByte = file->appByte;
+		
+		// Read into buffer
+		disc_ReadSector( FAT_ClustToSect(file->curClus) + file->curSect, file->readBuffer);
+		file->inUse = true;	// We're using this file now
+		return file;
+	}
+#endif
+
+	// Can only reach here if a bad mode was specified
+	return NULL;
+}
+
+/*-----------------------------------------------------------------
+FAT_fclose(file)
+Closes a file
+FAT_FILE* file: IN handle of the file to close
+bool return OUT: true if successful, false if not
+-----------------------------------------------------------------*/
+bool FAT_fclose (FAT_FILE* file)
+{
+	// Clear memory used by file information
+	if ((file != NULL) && (file->inUse == true))
+	{
+#ifdef CAN_WRITE_TO_DISC
+		if (file->write || file->append)
+		{
+			// Write new length, time and date back to directory entry
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].fileSize = file->length;
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].mTime = getRTCtoFileTime();
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].mDate = getRTCtoFileDate();
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].aDate = getRTCtoFileDate();
+
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+
+			// Flush any sectors in disc cache
+			disc_CacheFlush();
+		}
+#endif
+		file->inUse = false;		
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_ftell(file)
+Returns the current position in a file
+FAT_FILE* file: IN handle of an open file
+u32 OUT: Current position
+-----------------------------------------------------------------*/
+u32 FAT_ftell (FAT_FILE* file)
+{
+	// Return the position as specified in the FAT_FILE structure
+	if ((file != NULL) && (file->inUse == true))
+	{
+		return file->curPos;
+	}
+	else
+	{
+		// Return -1 if no file was given
+		return -1;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_fseek(file, offset, origin)
+Seeks to specified byte position in file
+FAT_FILE* file: IN handle of an open file
+s32 offset IN: position to seek to, relative to origin
+int origin IN: origin to seek from
+int OUT: Returns 0 if successful, -1 if not
+-----------------------------------------------------------------*/
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin)
+{
+	u32 cluster, nextCluster;
+	int clusCount;
+	u32 position;
+	u32 curPos;
+
+	if ((file == NULL) || (file->inUse == false))	// invalid file
+	{
+		return -1;
+	}
+
+	// Can't seek in append only mode
+	if (!file->read && !file->write)	
+	{
+		return -1;
+	}
+
+	curPos = file->curPos;
+
+	switch (origin) 
+	{
+	case SEEK_SET:
+		if (offset >= 0)
+		{
+			position = offset;
+		} else {
+			// Tried to seek before start of file
+			position = 0;
+		}
+		break;
+	case SEEK_CUR:
+		if (offset >= 0)
+		{
+			position = curPos + offset;
+		} 
+		else if ( (u32)(offset * -1) >= curPos )
+		{
+			// Tried to seek before start of file
+			position = 0;
+		}
+		else 
+		{
+			// Using u32 to maintain 32 bits of accuracy
+			position = curPos - (u32)(offset * -1);
+		}
+		break;
+	case SEEK_END:
+		if (offset >= 0)
+		{
+			// Seeking to end of file
+			position = file->length;	// Fixed thanks to MoonLight
+		}
+		else if ( (u32)(offset * -1) >= file->length )
+		{
+			// Tried to seek before start of file
+			position = 0;
+		}
+		else 
+		{
+			// Using u32 to maintain 32 bits of accuracy
+			position = file->length - (u32)(offset * -1);
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	if (position > file->length)
+	{
+		// Tried to go past end of file
+		position = file->length;
+	}
+	
+	// Save position
+	file->curPos = position;
+
+
+	// Calculate where the correct cluster is
+	if (position > curPos)
+	{
+		clusCount = (position - curPos + (file->curSect * filesysBytePerSec) + file->curByte) / filesysBytePerClus;	// Fixed thanks to AgentQ
+		cluster = file->curClus;
+	} else {
+		clusCount = position / filesysBytePerClus;
+		cluster = file->firstCluster;
+	}
+
+	// Calculate the sector and byte of the current position,
+	// and store them
+	file->curSect = (position % filesysBytePerClus) / BYTE_PER_READ;
+	file->curByte = position % BYTE_PER_READ;
+
+	// Follow cluster list until desired one is found
+	if (clusCount > 0)	// Only look at next cluster if need to
+	{
+		nextCluster = FAT_NextCluster (cluster);
+	} else {
+		nextCluster = cluster;
+	}
+	while ((clusCount--) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF))
+	{
+		cluster = nextCluster;
+		nextCluster = FAT_NextCluster (cluster);
+	}
+	// Check if ran out of clusters, and the file is being written to
+	if ((clusCount >= 0) && (file->write || file->append)) 
+	{
+		// Set flag to allocate a new cluster
+		file->curSect = filesysSecPerClus;
+		file->curByte = 0;
+	}
+	file->curClus = cluster;
+	
+	// Reload sector buffer for new position in file, if it is a different sector
+	if ((curPos ^ position) >= BYTE_PER_READ)
+	{
+		disc_ReadSector( file->curSect + FAT_ClustToSect(file->curClus), file->readBuffer);
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+FAT_fread(buffer, size, count, file)
+Reads in size * count bytes into buffer from file, starting
+	from current position. It then sets the current position to the
+	byte after the last byte read. If it reaches the end of file
+	before filling the buffer then it stops reading.
+void* buffer OUT: Pointer to buffer to fill. Should be at least as
+	big as the number of bytes required
+u32 size IN: size of each item to read
+u32 count IN: number of items to read
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes read
+-----------------------------------------------------------------*/
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file)
+{
+	int curByte;
+	int curSect;
+	u32 curClus;
+	u32 tempNextCluster;
+	
+	int tempVar;
+
+	char* data = (char*)buffer;
+
+	u32 length = size * count;
+	u32 remain;
+
+	bool flagNoError = true;
+
+	// Can't read non-existant files
+	if ((file == NULL) || (file->inUse == false) || size == 0 || count == 0 || buffer == NULL)
+		return 0;
+
+	// Can only read files openned for reading
+	if (!file->read)
+		return 0;
+
+	// Don't read past end of file
+	if (length + file->curPos > file->length)
+		length = file->length - file->curPos;
+
+	remain = length;
+
+	curByte = file->curByte;
+	curSect = file->curSect;
+	curClus = file->curClus;
+
+	// Align to sector
+	tempVar = BYTE_PER_READ - curByte;
+	if (tempVar > remain)
+		tempVar = remain;
+
+	if ((tempVar < BYTE_PER_READ) && flagNoError) 
+	{
+		memcpy(data, &(file->readBuffer[curByte]), tempVar);
+		remain -= tempVar;
+		data += tempVar;
+
+		curByte += tempVar;
+		if (curByte >= BYTE_PER_READ) 
+		{
+			curByte = 0;
+			curSect++;
+		}
+	}
+
+	// align to cluster
+	// tempVar is number of sectors to read
+	if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) 
+	{
+		tempVar = filesysSecPerClus - curSect;
+	} else {
+		tempVar = remain / BYTE_PER_READ;
+	}
+
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_ReadSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+
+		curSect += tempVar;
+	}
+
+	// Move onto next cluster
+	// It should get to here without reading anything if a cluster is due to be allocated
+	if (curSect >= filesysSecPerClus)
+	{
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((remain == 0) && (tempNextCluster == CLUSTER_EOF))
+		{
+			curSect = filesysSecPerClus;
+		} else {
+			curSect = 0;
+			curClus = tempNextCluster;
+			if (curClus == CLUSTER_FREE)
+			{
+				flagNoError = false;
+			}
+		}
+	}
+
+	// Read in whole clusters
+	while ((remain >= filesysBytePerClus) && flagNoError)
+	{
+		disc_ReadSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data);
+		data += filesysBytePerClus;
+		remain -= filesysBytePerClus;
+
+		// Advance to next cluster
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((remain == 0) && (tempNextCluster == CLUSTER_EOF))
+		{
+			curSect = filesysSecPerClus;
+		} else {
+			curSect = 0;
+			curClus = tempNextCluster;
+			if (curClus == CLUSTER_FREE)
+			{
+				flagNoError = false;
+			}
+		}
+	}
+
+	// Read remaining sectors
+	tempVar = remain / BYTE_PER_READ; // Number of sectors left
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_ReadSectors (FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+
+	// Last remaining sector
+	// Check if sector wanted is different to the one started with
+	if ( ((file->curByte + length) >= BYTE_PER_READ) && flagNoError)
+	{
+		disc_ReadSector( curSect + FAT_ClustToSect( curClus), file->readBuffer);
+		if (remain > 0)
+		{
+			memcpy(data, file->readBuffer, remain);
+			curByte += remain;
+			remain = 0;
+		}
+	}
+
+	// Length read is the wanted length minus the stuff not read
+	length = length - remain;
+
+	// Update file information
+	file->curByte = curByte;
+	file->curSect = curSect;
+	file->curClus = curClus;
+	file->curPos = file->curPos + length;
+	return length;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fwrite(buffer, size, count, file)
+Writes size * count bytes into file from buffer, starting
+	from current position. It then sets the current position to the
+	byte after the last byte written. If the file was openned in 
+	append mode it always writes to the end of the file.
+const void* buffer IN: Pointer to buffer containing data. Should be
+	at least as big as the number of bytes to be written.
+u32 size IN: size of each item to write
+u32 count IN: number of items to write
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes written
+-----------------------------------------------------------------*/
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file)
+{
+	int curByte;
+	int curSect;
+	u32 curClus;
+
+	u32 tempNextCluster;
+	int tempVar;
+	u32 length = size * count;
+	u32 remain = length;
+	char* data = (char*)buffer;
+
+	char* writeBuffer;
+
+	bool flagNoError = true;
+	bool flagAppending = false;
+
+	if ((file == NULL) || (file->inUse == false) || length == 0 || buffer == NULL)
+		return 0;
+
+	if (file->write)
+	{
+		// Write at current read pointer
+		curByte = file->curByte;
+		curSect = file->curSect;
+		curClus = file->curClus;
+
+		// Use read buffer as write buffer
+		writeBuffer = file->readBuffer;
+
+		// If it is writing past the current end of file, set appending flag
+		if (length + file->curPos > file->length)
+		{
+			flagAppending = true;
+		}
+	}
+	else if (file->append)
+	{
+		// Write at end of file
+		curByte = file->appByte;
+		curSect = file->appSect;
+		curClus = file->appClus;
+		flagAppending = true;
+
+		// Use global buffer as write buffer, don't touch read buffer
+		writeBuffer = (char*)globalBuffer;
+		disc_ReadSector(curSect + FAT_ClustToSect(curClus), writeBuffer);
+	}
+	else
+	{
+		return 0;
+	}
+
+	// Move onto next cluster if needed
+	if (curSect >= filesysSecPerClus)
+	{
+		curSect = 0;
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+		{
+			// Ran out of clusters so get a new one
+			curClus = FAT_LinkFreeCluster(curClus);
+			if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+			{
+				flagNoError = false;
+			}
+			memset(writeBuffer, 0, BYTE_PER_READ);
+		} else {
+			curClus = tempNextCluster;
+			disc_ReadSector( FAT_ClustToSect( curClus), writeBuffer);
+		}
+	}
+	
+	// Align to sector
+	tempVar = BYTE_PER_READ - curByte;
+	if (tempVar > remain)
+		tempVar = remain;
+
+	if ((tempVar < BYTE_PER_READ) && flagNoError)
+	{
+		memcpy(&(writeBuffer[curByte]), data, tempVar);
+		remain -= tempVar;
+		data += tempVar;
+		curByte += tempVar;
+
+		// Write buffer back to disk
+		disc_WriteSector (curSect + FAT_ClustToSect(curClus), writeBuffer);
+		
+		// Move onto next sector
+		if (curByte >= BYTE_PER_READ) 
+		{
+			curByte = 0;
+			curSect++;
+		}
+	}
+
+	// Align to cluster
+	// tempVar is number of sectors to write
+	if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) 
+	{
+		tempVar = filesysSecPerClus - curSect;
+	} else {
+		tempVar = remain / BYTE_PER_READ;
+	}
+
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_WriteSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+
+	if (((curSect >= filesysSecPerClus) && flagNoError) && (remain > 0))
+	{
+		curSect = 0;
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+		{
+			// Ran out of clusters so get a new one
+			curClus = FAT_LinkFreeCluster(curClus);
+			if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+			{
+				flagNoError = false;
+			}
+		} else {
+			curClus = tempNextCluster;
+		}
+	}
+
+	// Write whole clusters
+	while ((remain >= filesysBytePerClus) && flagNoError)
+	{
+		disc_WriteSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data);
+		data += filesysBytePerClus;
+		remain -= filesysBytePerClus;
+		if (remain > 0)
+		{
+			tempNextCluster = FAT_NextCluster(curClus);
+			if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+			{
+				// Ran out of clusters so get a new one
+				curClus = FAT_LinkFreeCluster(curClus);
+				if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+				{
+					flagNoError = false;
+					break;
+				}
+			} else {
+				curClus = tempNextCluster;
+			}
+		} else {
+			// Allocate a new cluster when next writing the file
+			curSect = filesysSecPerClus;
+		}
+	}
+
+	// Write remaining sectors
+	tempVar = remain / BYTE_PER_READ; // Number of sectors left
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_WriteSectors (FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+	
+	// Last remaining sector
+	// Check if sector wanted is different to the one started with
+	if ( (( (file->append ? file->appByte : file->curByte) + length) >= BYTE_PER_READ) && flagNoError)
+	{
+		if (flagAppending)
+		{
+			// Zero sector before using it
+			memset (writeBuffer, 0, BYTE_PER_READ);
+		} else {
+			// Modify existing sector
+			disc_ReadSector( curSect + FAT_ClustToSect( curClus), writeBuffer);
+		}
+		if (remain > 0) {
+			memcpy(writeBuffer, data, remain);
+			curByte += remain;
+			remain = 0;
+			disc_WriteSector( curSect + FAT_ClustToSect( curClus), writeBuffer);
+		}
+	}
+	
+	// Amount read is the originally requested amount minus stuff remaining
+	length = length - remain;
+
+	// Update file information
+	if (file->write)	// Writing also shifts the read pointer
+	{
+		file->curByte = curByte;
+		file->curSect = curSect;
+		file->curClus = curClus;
+		file->curPos = file->curPos + length;
+		if (file->length < file->curPos)
+		{
+			file->length = file->curPos;
+		}
+	}
+	else if (file->append)	// Appending doesn't affect the read pointer
+	{
+		file->appByte = curByte;
+		file->appSect = curSect;
+		file->appClus = curClus;
+		file->length = file->length + length;
+	}
+
+	return length;
+}
+#endif
+
+
+/*-----------------------------------------------------------------
+FAT_feof(file)
+Returns true if the end of file has been reached
+FAT_FILE* file IN: Handle of an open file
+bool return OUT: true if EOF, false if not
+-----------------------------------------------------------------*/
+bool FAT_feof(FAT_FILE* file)
+{
+	if ((file == NULL) || (file->inUse == false))
+		return true;	// Return eof on invalid files
+
+	return (file->length == file->curPos);
+}
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_remove (path)
+Deletes the file or empty directory sepecified in path
+const char* path IN: Path of item to delete
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_remove (const char* path)
+{
+	DIR_ENT dirEntry;
+	u32 oldWorkDirCluster;
+	char checkFilename[13];
+	FILE_TYPE checkFiletype;
+	
+	dirEntry = FAT_DirEntFromPath (path);
+
+	if (dirEntry.name[0] == FILE_FREE)
+	{
+		return -1;
+	}
+	
+	// Only delete directories if the directory is entry
+	if (dirEntry.attrib & ATTRIB_DIR)
+	{
+		// Change to the directory temporarily
+		oldWorkDirCluster = curWorkDirCluster;
+		FAT_chdir(path);
+
+		// Search for files or directories, excluding the . and .. entries
+		checkFiletype = FAT_FindFirstFile (checkFilename);
+		while ((checkFilename[0] == '.')  && (checkFiletype != FT_NONE))
+		{
+			checkFiletype = FAT_FindNextFile (checkFilename);
+		}
+		
+		// Change back to working directory
+		curWorkDirCluster = oldWorkDirCluster;
+		
+		// Check that the directory is empty
+		if (checkFiletype != FT_NONE)
+		{
+			// Directory isn't empty
+			return -1;
+		}
+	}
+
+	// Refresh directory information
+	dirEntry = FAT_DirEntFromPath (path);
+
+	// Free any clusters used
+	FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16));
+
+	// Remove Directory entry
+	disc_ReadSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer);
+	((DIR_ENT*)globalBuffer)[wrkDirOffset].name[0] = FILE_FREE;
+	disc_WriteSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer);
+		
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+
+	return 0;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_mkdir (path)
+Makes a new directory, so long as no other directory or file has 
+	the same name.
+const char* path IN: Path and filename of directory to make
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_mkdir (const char* path)
+{
+	u32 newDirCluster;
+	u32 parentDirCluster;
+	DIR_ENT dirEntry;
+	DIR_ENT* entries = (DIR_ENT*)globalBuffer;
+	int i;
+
+	int pathPos, filePos;
+	char pathname[MAX_FILENAME_LENGTH];
+	u32 oldDirCluster;
+
+	if (FAT_FileExists(path) != FT_NONE)
+	{
+		return -1;	// File or directory exists with that name
+	}
+
+	// Find filename within path and change to that directory
+	oldDirCluster = curWorkDirCluster;
+	if (path[0] == '/')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+	}
+	
+	pathPos = 0;
+	filePos = 0;
+
+	while (path[pathPos + filePos] != '\0')
+	{
+		if (path[pathPos + filePos] == '/')
+		{
+			pathname[filePos] = '\0';
+			if (FAT_chdir(pathname) == false) 
+			{
+				curWorkDirCluster = oldDirCluster;
+				return -1; // Couldn't change directory
+			}
+			pathPos += filePos + 1;
+			filePos = 0;
+		}
+		pathname[filePos] = path[pathPos + filePos];
+		filePos++;
+	}
+
+	// Now grab the parent directory's cluster
+	parentDirCluster = curWorkDirCluster;
+	curWorkDirCluster = oldDirCluster;
+
+	// Get a new cluster for the file
+	newDirCluster = FAT_LinkFreeCluster(CLUSTER_FREE);
+
+	if (newDirCluster == CLUSTER_FREE)
+	{
+		return -1;	// Couldn't get a new cluster for the directory
+	}
+	// Fill in directory entry's information
+	dirEntry.attrib = ATTRIB_DIR;
+	dirEntry.reserved = 0;
+	// Time and date set to system time and date
+	dirEntry.cTime_ms = 0;
+	dirEntry.cTime = getRTCtoFileTime();
+	dirEntry.cDate = getRTCtoFileDate();
+	dirEntry.aDate = getRTCtoFileDate();
+	dirEntry.mTime = getRTCtoFileTime();
+	dirEntry.mDate = getRTCtoFileDate();
+	// Store cluster position into the directory entry
+	dirEntry.startCluster = (newDirCluster & 0xFFFF);
+	dirEntry.startClusterHigh = ((newDirCluster >> 16) & 0xFFFF);
+	// The file has no data in it - its over written so should be empty
+	dirEntry.fileSize = 0;
+
+	if (FAT_AddDirEntry (path, dirEntry) == false)
+	{
+		return -1;	// Couldn't add the directory entry
+	}
+
+	// Create the new directory itself
+	memset(entries, FILE_LAST, BYTE_PER_READ);
+
+	// Create . directory entry
+	dirEntry.name[0] = '.';
+	// Fill name and extension with spaces
+	for (i = 1; i < 11; i++)
+	{
+		dirEntry.name[i] = ' ';
+	}
+
+	memcpy(entries, &dirEntry, sizeof(dirEntry));
+
+	// Create .. directory entry
+	dirEntry.name[1] = '.';
+	dirEntry.startCluster = (parentDirCluster & 0xFFFF);
+	dirEntry.startClusterHigh = ((parentDirCluster >> 16) & 0xFFFF);
+
+	memcpy(&entries[1], &dirEntry, sizeof(dirEntry));
+
+	// Write entry to disc
+	disc_WriteSector(FAT_ClustToSect(newDirCluster), entries);
+
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+	return 0;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgetc (handle)
+Gets the next character in the file
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fgetc (FAT_FILE* file)
+{
+	char c;
+	return (FAT_fread(&c, 1, 1, file) == 1) ? c : EOF;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputc (character, handle)
+Writes the given character into the file
+char c IN: Character to be written
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fputc (char c, FAT_FILE* file)
+{
+	return (FAT_fwrite(&c, 1, 1, file) == 1) ? c : EOF;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgets (char *tgtBuffer, int num, FAT_FILE* file)
+Gets a up to num bytes from file, stopping at the first
+ newline.
+
+CAUTION: does not do strictly streaming. I.e. it's 
+ reading more then needed bytes and seeking back.
+ shouldn't matter for random access 
+
+char *tgtBuffer OUT: buffer to write to
+int num IN: size of target buffer
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Added check for unix style text files
+	* Removed seek when no newline is found, since it isn't necessary
+-------------------------------------------------------------------*/
+char *FAT_fgets(char *tgtBuffer, int num, FAT_FILE* file) 
+{ 
+	u32 curPos;
+	u32 readLength;
+	char *returnChar;
+	
+	// invalid filehandle 
+	if (file == NULL)
+	{
+		return NULL ; 
+	}
+	
+	// end of file 
+	if (FAT_feof(file)==true)
+	{
+		return NULL ; 
+	}
+	
+	// save current position 
+	curPos = FAT_ftell(file); 
+	
+	// read the full buffer (max string chars is num-1 and one end of string \0 
+	readLength = FAT_fread(tgtBuffer,1,num-1,file) ; 
+	
+	// mark least possible end of string 
+	tgtBuffer[readLength] = '\0' ;    
+	
+	if (readLength==0) { 
+		// return error 
+		return NULL ; 
+	}
+	
+	// get position of first return '\r' 
+	returnChar = strchr(tgtBuffer,'\r'); 
+	
+	// if no return is found, search for a newline
+	if (returnChar == NULL)
+	{
+		returnChar = strchr(tgtBuffer,'\n');
+	}
+	
+	// Mark the return, if existant, as end of line/string 
+	if (returnChar!=NULL) { 
+		*returnChar++ = 0 ; 
+		if (*returnChar=='\n') { // catch newline too when jumping over the end 
+			// return to location after \r\n (strlen+2) 
+			FAT_fseek(file,curPos+strlen(tgtBuffer)+2,SEEK_SET) ; 
+			return tgtBuffer ; 
+		} else { 
+			// return to location after \r (strlen+1) 
+			FAT_fseek(file,curPos+strlen(tgtBuffer)+1,SEEK_SET) ; 
+			return tgtBuffer ; 
+		}
+	}
+	
+	return tgtBuffer ; 
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputs (const char *string, FAT_FILE* file)
+Writes string to file, excluding end of string character
+const char *string IN: string to write
+FAT_FILE* file IN: Handle of open file
+bool return OUT: number of characters written if successful,
+	EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Uses FAT_FILE instead of int
+	* writtenBytes is now u32 instead of int
+-------------------------------------------------------------------*/
+int FAT_fputs (const char *string, FAT_FILE* file) 
+{ 
+   u32 writtenBytes;
+	// save string except end of string '\0' 
+   writtenBytes = FAT_fwrite((void *)string, 1, strlen(string), file); 
+
+   // check if we had an error 
+   if (writtenBytes != strlen(string)) 
+   { 
+      // return EOF error 
+      return EOF;
+   }
+
+   // return the charcount written 
+   return writtenBytes ; 
+}
+#endif
+
+
+
+/*
+	gba_nds_fat.c
+	By chishm (Michael Chisholm)
+
+	Routines for reading a compact flash card
+	using the GBA Movie Player or M3.
+
+	Some FAT routines are based on those in fat.c, which
+	is part of avrlib by Pascal Stang.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+//---------------------------------------------------------------
+// Includes
+
+#include "gba_nds_fat.h"
+#include "disc_io.h"
+#include <string.h>
+#ifdef NDS
+ #include <nds/ipc.h>	// Time on the NDS
+#endif
+//----------------------------------------------------------------
+// Data	types
+#ifndef	NULL
+ #define	NULL	0
+#endif
+
+//----------------------------------------------------------------
+// NDS memory access control register
+#ifdef NDS
+ #ifndef WAIT_CR
+  #define WAIT_CR (*(vu16*)0x04000204)
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// Appropriate placement of CF functions and data
+#ifdef NDS
+ #define _VARS_IN_RAM 
+#else
+ #define _VARS_IN_RAM __attribute__ ((section (".sbss")))
+#endif
+
+
+//-----------------------------------------------------------------
+// FAT constants
+#define CLUSTER_EOF_16	0xFFFF
+#define	CLUSTER_EOF	0x0FFFFFFF
+#define CLUSTER_FREE	0x0000
+#define CLUSTER_FIRST	0x0002
+
+#define FILE_LAST 0x00
+#define FILE_FREE 0xE5
+
+#define FAT16_ROOT_DIR_CLUSTER 0x00
+
+
+//-----------------------------------------------------------------
+// long file name constants
+#define LFN_END 0x40
+#define LFN_DEL 0x80
+
+//-----------------------------------------------------------------
+// Data Structures
+
+// Take care of packing for GCC - it doesn't obey pragma pack()
+// properly for ARM targets.
+#ifdef __GNUC__
+ #define __PACKED __attribute__ ((__packed__))
+#else
+ #define __PACKED 
+ #pragma pack(1)
+#endif
+
+// Boot Sector - must be packed
+typedef struct
+{
+	u8	jmpBoot[3];
+	u8	OEMName[8];
+	// BIOS Parameter Block
+	u16	bytesPerSector;
+	u8	sectorsPerCluster;
+	u16	reservedSectors;
+	u8	numFATs;
+	u16	rootEntries;
+	u16	numSectorsSmall;
+	u8	mediaDesc;
+	u16	sectorsPerFAT;
+	u16	sectorsPerTrk;
+	u16	numHeads;
+	u32	numHiddenSectors;
+	u32	numSectors;
+	union	// Different types of extended BIOS Parameter Block for FAT16 and FAT32
+	{
+		struct  
+		{
+			// Ext BIOS Parameter Block for FAT16
+			u8	driveNumber;
+			u8	reserved1;
+			u8	extBootSig;
+			u32	volumeID;
+			u8	volumeLabel[11];
+			u8	fileSysType[8];
+			// Bootcode
+			u8	bootCode[448];
+		}	__PACKED fat16;
+		struct  
+		{
+			// FAT32 extended block
+			u32	sectorsPerFAT32;
+			u16	extFlags;
+			u16	fsVer;
+			u32	rootClus;
+			u16	fsInfo;
+			u16	bkBootSec;
+			u8	reserved[12];
+			// Ext BIOS Parameter Block for FAT16
+			u8	driveNumber;
+			u8	reserved1;
+			u8	extBootSig;
+			u32	volumeID;
+			u8	volumeLabel[11];
+			u8	fileSysType[8];
+			// Bootcode
+			u8	bootCode[420];
+		}	__PACKED fat32;
+	}	__PACKED extBlock;
+
+	u16	bootSig;
+
+}	__PACKED BOOT_SEC;
+
+// Directory entry - must be packed
+typedef struct
+{
+	u8	name[8];
+	u8	ext[3];
+	u8	attrib;
+	u8	reserved;
+	u8	cTime_ms;
+	u16	cTime;
+	u16	cDate;
+	u16	aDate;
+	u16	startClusterHigh;
+	u16	mTime;
+	u16	mDate;
+	u16	startCluster;
+	u32	fileSize;
+}	__PACKED DIR_ENT;
+
+// Long file name directory entry - must be packed
+typedef struct
+{
+	u8 ordinal;	// Position within LFN
+	u16 char0;	
+	u16 char1;
+	u16 char2;
+	u16 char3;
+	u16 char4;
+	u8 flag;	// Should be equal to ATTRIB_LFN
+	u8 reserved1;	// Always 0x00
+	u8 checkSum;	// Checksum of short file name (alias)
+	u16 char5;
+	u16 char6;
+	u16 char7;
+	u16 char8;
+	u16 char9;
+	u16 char10;
+	u16 reserved2;	// Always 0x0000
+	u16 char11;
+	u16 char12;
+}	__PACKED DIR_ENT_LFN;
+
+const char lfn_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E}; 
+
+// End of packed structs
+#ifdef __PACKED
+ #undef __PACKED
+#endif
+#ifndef __GNUC__
+ #pragma pack()
+#endif
+
+//-----------------------------------------------------------------
+// Global Variables
+
+// _VARS_IN_RAM variables are stored in the largest section of WRAM 
+// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA
+
+// Files
+_VARS_IN_RAM FAT_FILE openFiles[MAX_FILES_OPEN];
+
+// Long File names
+_VARS_IN_RAM char lfnName[MAX_FILENAME_LENGTH];
+bool lfnExists;
+
+// Locations on card
+int filesysRootDir;
+int filesysRootDirClus;
+int filesysFAT;
+int filesysSecPerFAT;
+int filesysNumSec;
+int filesysData;
+int filesysBytePerSec;
+int filesysSecPerClus;
+int filesysBytePerClus;
+
+FS_TYPE filesysType = FS_UNKNOWN;
+u32 filesysTotalSize;
+
+// Info about FAT
+u32 fatLastCluster;
+u32 fatFirstFree;
+
+// fatBuffer used to reduce wear on the CF card from multiple writes
+_VARS_IN_RAM char fatBuffer[BYTE_PER_READ];
+u32 fatBufferCurSector;
+
+// Current working directory
+u32 curWorkDirCluster;
+
+// Position of the directory entry last retreived with FAT_GetDirEntry
+u32 wrkDirCluster;
+int wrkDirSector;
+int wrkDirOffset;
+
+// Global sector buffer to save on stack space
+_VARS_IN_RAM unsigned char globalBuffer[BYTE_PER_READ];
+
+//-----------------------------------------------------------------
+// Functions contained in this file - predeclarations
+char ucase (char character);
+u16 getRTCtoFileTime (void);
+u16 getRTCtoFileDate (void);
+
+bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry);
+bool FAT_ClearLinks (u32 cluster);
+DIR_ENT FAT_DirEntFromPath (const char* path);
+u32 FAT_FirstFreeCluster(void);
+DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin);
+u32 FAT_LinkFreeCluster(u32 cluster);
+u32 FAT_NextCluster(u32 cluster);
+bool FAT_WriteFatEntry (u32 cluster, u32 value);
+bool FAT_GetFilename (DIR_ENT dirEntry, char* alias);
+
+bool FAT_InitFiles (void);
+bool FAT_FreeFiles (void);
+int FAT_remove (const char* path);
+bool FAT_chdir (const char* path);
+FILE_TYPE FAT_FindFirstFile (char* filename);
+FILE_TYPE FAT_FindNextFile (char* filename);
+FILE_TYPE FAT_FileExists (const char* filename);
+bool FAT_GetAlias (char* alias);
+bool FAT_GetLongFilename (char* filename);
+u32 FAT_GetFileSize (void);
+u32 FAT_GetFileCluster (void);
+
+FAT_FILE* FAT_fopen(const char* path, const char* mode);
+bool FAT_fclose (FAT_FILE* file);
+bool FAT_feof(FAT_FILE* file);
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin);
+u32 FAT_ftell (FAT_FILE* file);
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file);
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file);
+char FAT_fgetc (FAT_FILE* file);
+char FAT_fputc (char c, FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+ucase
+Returns the uppercase version of the given char
+char IN: a character
+char return OUT: uppercase version of character
+-----------------------------------------------------------------*/
+char ucase (char character)
+{
+	if ((character > 0x60) && (character < 0x7B))
+		character = character - 0x20;
+	return (character);
+}
+
+
+/*-----------------------------------------------------------------
+getRTCtoFileTime and getRTCtoFileDate
+Returns the time / date in Dir Entry styled format
+u16 return OUT: time / date in Dir Entry styled format
+-----------------------------------------------------------------*/
+u16 getRTCtoFileTime (void)
+{
+#ifdef NDS
+	return (
+		( ( (IPC->rtc_hours > 11 ? IPC->rtc_hours - 40 : IPC->rtc_hours) & 0x1F) << 11) |
+		( (IPC->rtc_minutes & 0x3F) << 5) |
+		( (IPC->rtc_seconds >> 1) & 0x1F) );
+#else
+	return 0;
+#endif
+}
+
+u16 getRTCtoFileDate (void)
+{
+#ifdef NDS
+	return ( 
+		( ((IPC->rtc_year + 20) & 0x7F) <<9) |
+		( (IPC->rtc_month & 0xF) << 5) |
+		(IPC->rtc_day & 0x1F) );
+#else
+	return 0;
+#endif
+}
+
+
+/*-----------------------------------------------------------------
+Disc level FAT routines
+-----------------------------------------------------------------*/
+#define FAT_ClustToSect(m) \
+	(((m-2) * filesysSecPerClus) + filesysData)
+
+/*-----------------------------------------------------------------
+FAT_NextCluster
+Internal function - gets the cluster linked from input cluster
+-----------------------------------------------------------------*/
+u32 FAT_NextCluster(u32 cluster)
+{
+	u32 nextCluster = CLUSTER_FREE;
+	u32 sector;
+	int offset;
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			nextCluster = CLUSTER_FREE;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			nextCluster = ((u8*)fatBuffer)[offset];
+			offset++;
+			
+			if (offset >= BYTE_PER_READ) {
+				offset = 0;
+				fatBufferCurSector++;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+			
+			nextCluster |= (((u8*)fatBuffer)[offset]) << 8;
+			
+			if (cluster & 0x01) {
+				nextCluster = nextCluster >> 4;
+			} else 	{
+				nextCluster &= 0x0FFF;
+			}
+			
+			if (nextCluster >= 0x0FF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// read the nextCluster value
+			nextCluster = ((u16*)fatBuffer)[offset];
+			
+			if (nextCluster >= 0xFFF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// read the nextCluster value
+			nextCluster = (((u32*)fatBuffer)[offset]) & 0x0FFFFFFF;
+			
+			if (nextCluster >= 0x0FFFFFF7)
+			{
+				nextCluster = CLUSTER_EOF;
+			}
+			break;
+			
+		default:
+			nextCluster = CLUSTER_FREE;
+			break;
+	}
+	
+	return nextCluster;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_WriteFatEntry
+Internal function - writes FAT information about a cluster
+-----------------------------------------------------------------*/
+bool FAT_WriteFatEntry (u32 cluster, u32 value)
+{
+	u32 sector;
+	int offset;
+
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+	{
+		return false;
+	}
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			return false;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			if (cluster & 0x01) {
+
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4);
+
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				((u8*)fatBuffer)[offset] =  (value & 0x0FF0) >> 4;
+
+			} else {
+			
+				((u8*)fatBuffer)[offset] = value & 0xFF;
+		
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F);
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			((u16*)fatBuffer)[offset] = (value & 0xFFFF);
+
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			(((u32*)fatBuffer)[offset]) =  value;
+
+			break;
+			
+		default:
+			return false;
+			break;
+	}
+	
+	// write the buffer back to disc
+	disc_WriteSector(fatBufferCurSector, fatBuffer);
+			
+	return true;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_ReadWriteFatEntryBuffered
+Internal function - writes FAT information about a cluster to a 
+ buffer that should then be flushed to disc using 
+ FAT_WriteFatEntryFlushBuffer()
+ Call FAT_WriteFatEntry first so as not to ruin the disc.
+ Also returns the entry being replaced
+-----------------------------------------------------------------*/
+u32 FAT_ReadWriteFatEntryBuffered (u32 cluster, u32 value)
+{
+	u32 sector;
+	int offset;
+	u32 oldValue;
+
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+		return CLUSTER_FREE;
+
+	
+	switch (filesysType) 
+	{
+		case FS_UNKNOWN:
+			oldValue = CLUSTER_FREE;
+			break;
+			
+		case FS_FAT12:
+			sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
+			offset = ((cluster * 3) / 2) % BYTE_PER_READ;
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			if (cluster & 0x01) {
+
+				oldValue = (((u8*)fatBuffer)[offset] & 0xF0) >> 4;
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4);
+
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				oldValue |= ((((u8*)fatBuffer)[offset]) << 4) & 0x0FF0;
+				((u8*)fatBuffer)[offset] =  (value & 0x0FF0) >> 4;
+
+			} else {
+			
+				oldValue = ((u8*)fatBuffer)[offset] & 0xFF;
+				((u8*)fatBuffer)[offset] = value & 0xFF;
+		
+				offset++;
+				if (offset >= BYTE_PER_READ) {
+					offset = 0;
+					// write the buffer back to disc
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+					// read the next sector	
+					fatBufferCurSector++;
+					disc_ReadSector(fatBufferCurSector, fatBuffer);
+				}
+				
+				oldValue |= (((u8*)fatBuffer)[offset] & 0x0F) << 8;
+				((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F);
+			}
+
+			if (oldValue >= 0x0FF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT16:
+			sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 1);
+
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			} 
+
+			// write the value to the FAT buffer
+			oldValue = ((u16*)fatBuffer)[offset];
+			((u16*)fatBuffer)[offset] = value;
+
+			if (oldValue >= 0xFFF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		case FS_FAT32:
+			sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
+			offset = cluster % (BYTE_PER_READ >> 2);
+			
+			// If FAT buffer contains wrong sector
+			if (sector != fatBufferCurSector)
+			{
+				// write the old buffer to disc
+				if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+					disc_WriteSector(fatBufferCurSector, fatBuffer);
+				// Load correct sector to buffer
+				fatBufferCurSector = sector;
+				disc_ReadSector(fatBufferCurSector, fatBuffer);
+			}
+
+			// write the value to the FAT buffer
+			oldValue = ((u32*)fatBuffer)[offset];
+			((u32*)fatBuffer)[offset] =  value;
+
+			if (oldValue >= 0x0FFFFFF7) 
+			{
+				oldValue = CLUSTER_EOF;
+			}
+
+			break;
+			
+		default:
+			oldValue = CLUSTER_FREE;
+			break;
+	}
+	
+	return oldValue;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_WriteFatEntryFlushBuffer
+Flush the FAT buffer back to the disc
+-----------------------------------------------------------------*/
+bool FAT_WriteFatEntryFlushBuffer (void)
+{
+	// write the buffer disc
+	if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT)))
+	{
+		disc_WriteSector(fatBufferCurSector, fatBuffer);
+		return true;
+	} else {
+		return false;
+	}
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_FirstFreeCluster
+Internal function - gets the first available free cluster
+-----------------------------------------------------------------*/
+u32 FAT_FirstFreeCluster(void)
+{
+	// Start at first valid cluster
+	if (fatFirstFree < CLUSTER_FIRST)
+		fatFirstFree = CLUSTER_FIRST;
+
+	while ((FAT_NextCluster(fatFirstFree) != CLUSTER_FREE) && (fatFirstFree <= fatLastCluster))
+	{
+		fatFirstFree++;
+	}
+	if (fatFirstFree > fatLastCluster)
+	{
+		return CLUSTER_EOF;
+	}
+	return fatFirstFree;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_LinkFreeCluster
+Internal function - gets the first available free cluster, sets it
+to end of file, links the input cluster to it then returns the 
+cluster number
+-----------------------------------------------------------------*/
+u32 FAT_LinkFreeCluster(u32 cluster)
+{
+	u32 firstFree;
+	u32 curLink;
+
+	if (cluster > fatLastCluster)
+	{
+		return CLUSTER_FREE;
+	}
+
+	// Check if the cluster already has a link, and return it if so
+	curLink = FAT_NextCluster (cluster);
+	if ((curLink >= CLUSTER_FIRST) && (curLink < fatLastCluster))
+	{
+		return curLink;	// Return the current link - don't allocate a new one
+	}
+	
+	// Get a free cluster
+	firstFree = FAT_FirstFreeCluster();
+
+	// If couldn't get a free cluster then return
+	if (firstFree == CLUSTER_EOF)
+	{
+		return CLUSTER_FREE;
+	}
+
+	if ((cluster >= CLUSTER_FIRST) && (cluster < fatLastCluster))
+	{
+		// Update the linked from FAT entry
+		FAT_WriteFatEntry (cluster, firstFree);
+	}
+	// Create the linked to FAT entry
+	FAT_WriteFatEntry (firstFree, CLUSTER_EOF);
+
+	return firstFree;
+}
+#endif
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_ClearLinks
+Internal function - frees any cluster used by a file
+-----------------------------------------------------------------*/
+bool FAT_ClearLinks (u32 cluster)
+{
+	u32 nextCluster;
+	
+	if ((cluster < 0x0002) || (cluster > fatLastCluster))
+		return false;
+
+	// Store next cluster before erasing the link
+	nextCluster = FAT_NextCluster (cluster);
+
+	// Erase the link
+	FAT_WriteFatEntry (cluster, CLUSTER_FREE);
+
+	// Move onto next cluster
+	cluster = nextCluster;
+
+	while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE))
+	{
+		cluster = FAT_ReadWriteFatEntryBuffered (cluster, CLUSTER_FREE);
+	} 
+
+	// Flush fat write buffer
+	FAT_WriteFatEntryFlushBuffer ();
+
+	return true;
+}
+#endif
+
+
+/*-----------------------------------------------------------------
+FAT_InitFiles
+Reads the FAT information from the CF card.
+You need to call this before reading any files.
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_InitFiles (void)
+{
+	int i;
+	int bootSector;
+	BOOT_SEC* bootSec;
+	
+	if (!disc_Init())
+	{
+		return (false);
+	}
+	
+	// Read first sector of CF card
+	if ( !disc_ReadSector(0, globalBuffer)) {
+		return false;
+	}
+
+	// Make sure it is a valid MBR or boot sector
+	if ( (globalBuffer[0x1FE] != 0x55) || (globalBuffer[0x1FF] != 0xAA)) {
+		return false;
+	}
+
+	// Check if there is a FAT string, which indicates this is a boot sector
+	if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T'))
+	{
+		bootSector = 0;
+	}
+	// Check for FAT32
+	else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T'))
+	{
+		bootSector = 0;
+	}
+	else	// This is an MBR
+	{
+		// Find first valid partition from MBR
+		// First check for an active partition
+		for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10);
+		// If it didn't find an active partition, search for any valid partition
+		if (i == 0x1FE) 
+			for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10);
+		
+		// Go to first valid partition
+		if ( i != 0x1FE)	// Make sure it found a partition
+		{
+			bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F);
+		} else {
+			bootSector = 0;	// No partition found, assume this is a MBR free disk
+		}
+	}
+
+	// Read in boot sector
+	bootSec = (BOOT_SEC*) globalBuffer;
+	if (!disc_ReadSector (bootSector,  bootSec)) {
+		return false;
+	}
+	
+	// Store required information about the file system
+	if (bootSec->sectorsPerFAT != 0)
+	{
+		filesysSecPerFAT = bootSec->sectorsPerFAT;
+	}
+	else
+	{
+		filesysSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32;
+	}
+	
+	if (bootSec->numSectorsSmall != 0)
+	{
+		filesysNumSec = bootSec->numSectorsSmall;
+	}
+	else
+	{
+		filesysNumSec = bootSec->numSectors;
+	}
+
+	filesysBytePerSec = BYTE_PER_READ;	// Sector size is redefined to be 512 bytes
+	filesysSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTE_PER_READ;
+	filesysBytePerClus = filesysBytePerSec * filesysSecPerClus;
+	filesysFAT = bootSector + bootSec->reservedSectors;
+
+	filesysRootDir = filesysFAT + (bootSec->numFATs * filesysSecPerFAT);
+	filesysData = filesysRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / filesysBytePerSec);
+
+	filesysTotalSize = (filesysNumSec - filesysData) * filesysBytePerSec;
+
+	// Store info about FAT
+	fatLastCluster = (filesysNumSec - filesysData) / bootSec->sectorsPerCluster;
+	fatFirstFree = CLUSTER_FIRST;
+	fatBufferCurSector = 0;
+	disc_ReadSector(fatBufferCurSector, fatBuffer);
+
+	if (fatLastCluster < 4085)
+	{
+		filesysType = FS_FAT12;	// FAT12 volume - unsupported
+	}
+	else if (fatLastCluster < 65525)
+	{
+		filesysType = FS_FAT16;	// FAT16 volume
+	}
+	else
+	{
+		filesysType = FS_FAT32;	// FAT32 volume
+	}
+
+	if (filesysType != FS_FAT32)
+	{
+		filesysRootDirClus = FAT16_ROOT_DIR_CLUSTER;
+	}
+	else	// Set up for the FAT32 way
+	{
+		filesysRootDirClus = bootSec->extBlock.fat32.rootClus;
+		// Check if FAT mirroring is enabled
+		if (!(bootSec->extBlock.fat32.extFlags & 0x80))
+		{
+			// Use the active FAT
+			filesysFAT = filesysFAT + ( filesysSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F));
+		}
+	}
+
+	// Set current directory to the root
+	curWorkDirCluster = filesysRootDirClus;
+	wrkDirCluster = filesysRootDirClus;
+	wrkDirSector = 0;
+	wrkDirOffset = 0;
+
+	// Set all files to free
+	for (i=0; i < MAX_FILES_OPEN; i++)
+	{
+		openFiles[i].inUse = false;
+	}
+
+	// No long filenames so far
+	lfnExists = false;
+	for (i = 0; i < MAX_FILENAME_LENGTH; i++)
+	{
+		lfnName[i] = '\0';
+	}
+
+	return (true);
+}
+
+/*-----------------------------------------------------------------
+FAT_FreeFiles
+Closes all open files then resets the CF card.
+Call this before exiting back to the GBAMP
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_FreeFiles (void)
+{
+	int i;
+
+	// Close all open files
+	for (i=0; i < MAX_FILES_OPEN; i++)
+	{
+		if (openFiles[i].inUse == true)
+		{
+			FAT_fclose(&openFiles[i]);
+		}
+	}
+
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+
+	// Clear card status
+	disc_ClearStatus();
+
+	// Return status of card
+	return disc_IsInserted();
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetDirEntry
+Return the file info structure of the next valid file entry
+u32 dirCluster: IN cluster of subdirectory table
+int entry: IN the desired file entry
+int origin IN: relative position of the entry
+DIR_ENT return OUT: desired dirEntry. First char will be FILE_FREE if 
+	the entry does not exist.
+-----------------------------------------------------------------*/
+DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin)
+{
+	DIR_ENT dir;
+	DIR_ENT_LFN lfn;
+	int firstSector = 0;
+	bool notFound = false;
+	bool found = false;
+	int maxSectors;
+	int lfnPos, aliasPos;
+	u8 lfnChkSum, chkSum;
+
+	int i;
+
+	dir.name[0] = FILE_FREE; // default to no file found
+	dir.attrib = 0x00;
+
+	// Check if fat has been initialised
+	if (filesysBytePerSec == 0)
+	{
+		return (dir);
+	}
+	
+	switch (origin) 
+	{
+	case SEEK_SET:
+		wrkDirCluster = dirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		break;
+	case SEEK_CUR:	// Don't change anything
+		break;
+	case SEEK_END:	// Find entry signifying end of directory
+		// Subtraction will never reach 0, so it keeps going 
+		// until reaches end of directory
+		wrkDirCluster = dirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		entry = -1;
+		break;
+	default:
+		return dir;
+	}
+
+	lfnChkSum = 0;
+	maxSectors = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus);
+
+	// Scan Dir for correct entry
+	firstSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster));
+	disc_ReadSector (firstSector + wrkDirSector, globalBuffer);
+	found = false;
+	notFound = false;
+	do {
+		wrkDirOffset++;
+		if (wrkDirOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			wrkDirOffset = 0;
+			wrkDirSector++;
+			if ((wrkDirSector == filesysSecPerClus) && (wrkDirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				wrkDirSector = 0;
+				wrkDirCluster = FAT_NextCluster(wrkDirCluster);
+				if (wrkDirCluster == CLUSTER_EOF)
+				{
+					notFound = true;
+				}
+				firstSector = FAT_ClustToSect(wrkDirCluster);		
+			}
+			else if ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER) && (wrkDirSector == (filesysData - filesysRootDir)))
+			{
+				notFound = true;	// Got to end of root dir
+			}
+			disc_ReadSector (firstSector + wrkDirSector, globalBuffer);
+		}
+		dir = ((DIR_ENT*) globalBuffer)[wrkDirOffset];
+		if ((dir.name[0] != FILE_FREE) && (dir.name[0] > 0x20) && ((dir.attrib & ATTRIB_VOL) != ATTRIB_VOL))
+		{
+			entry--;
+			if (lfnExists)
+			{
+				// Calculate file checksum
+				chkSum = 0;
+				for (aliasPos=0; aliasPos < 11; aliasPos++)
+				{
+					// NOTE: The operation is an unsigned char rotate right
+					chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + (aliasPos < 8 ? dir.name[aliasPos] : dir.ext[aliasPos - 8]);
+				}
+				if (chkSum != lfnChkSum)
+				{
+					lfnExists = false;
+					lfnName[0] = '\0';
+				}
+			}
+			if (entry == 0) 
+			{
+				if (!lfnExists)
+				{
+					FAT_GetFilename (dir, lfnName);
+				}
+				found = true;
+			}
+		}
+		else if (dir.name[0] == FILE_LAST)
+		{
+			if (origin == SEEK_END)
+			{
+				found = true;
+			}
+			else
+			{
+				notFound = true;
+			}
+		}
+		else if (dir.attrib == ATTRIB_LFN)
+		{
+			lfn = ((DIR_ENT_LFN*) globalBuffer)[wrkDirOffset];
+			if (lfn.ordinal & LFN_DEL)
+			{
+				lfnExists = false;
+			}
+			else if (lfn.ordinal & LFN_END)	// Last part of LFN, make sure it isn't deleted (Thanks MoonLight)
+			{
+				lfnExists = true;
+				lfnName[(lfn.ordinal & ~LFN_END) * 13] = '\0';	// Set end of lfn to null character
+				lfnChkSum = lfn.checkSum;
+			}
+			if (lfnChkSum != lfn.checkSum)
+			{
+				lfnExists = false;
+			}
+			if (lfnExists)
+			{
+				lfnPos = ((lfn.ordinal & ~LFN_END) - 1) * 13;
+				for (i = 0; i < 13; i++) {
+					lfnName[lfnPos + i] = ((u8*)&lfn)[(int)(lfn_offset_table[i])] /* | ((u8*)&lfn)[(int)(lfn_offset_table[i]) + 1]  include this for unicode support*/;
+				}
+			}
+		}
+	} while (!found && !notFound);
+	
+	// If no file is found, return FILE_FREE
+	if (notFound)
+	{
+		dir.name[0] = FILE_FREE;
+	}
+
+	return (dir);
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetLongFilename
+Get the long name of the last file or directory retrived with 
+	GetDirEntry. Also works for FindFirstFile and FindNextFile.
+	If a long name doesn't exist, it returns the short name
+	instead.
+char* filename: OUT will be filled with the filename, should be at
+	least 256 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetLongFilename (char* filename)
+{
+	if (filename == NULL)
+		return false;
+
+	strncpy (filename, lfnName, MAX_FILENAME_LENGTH - 1);
+	filename[MAX_FILENAME_LENGTH - 1] = '\0';
+	
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+FAT_GetFilename
+Get the alias (short name) of the file or directory stored in 
+	dirEntry
+DIR_ENT dirEntry: IN a valid directory table entry
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetFilename (DIR_ENT dirEntry, char* alias)
+{
+	int i=0;
+	int j=0;
+
+	alias[0] = '\0';
+	if (dirEntry.name[0] != FILE_FREE)
+	{
+		if (dirEntry.name[0] == '.')
+		{
+			alias[0] = '.';
+			if (dirEntry.name[1] == '.')
+			{
+				alias[1] = '.';
+				alias[2] = '\0';
+			}
+			else
+			{
+				alias[1] = '\0';
+			}
+		}
+		else
+		{		
+			// Copy the filename from the dirEntry to the string
+			for (i = 0; (i < 8) && (dirEntry.name[i] != ' '); i++)
+			{
+				alias[i] = dirEntry.name[i];
+			}
+			// Copy the extension from the dirEntry to the string
+			if (dirEntry.ext[0] != ' ')
+			{
+				alias[i++] = '.';
+				for ( j = 0; (j < 3) && (dirEntry.ext[j] != ' '); j++)
+				{
+					alias[i++] = dirEntry.ext[j];
+				}
+			}
+			alias[i] = '\0';
+		}
+	}
+
+	return (alias[0] != '\0');
+}
+
+/*-----------------------------------------------------------------
+FAT_GetAlias
+Get the alias (short name) of the last file or directory entry read
+	using GetDirEntry. Works for FindFirstFile and FindNextFile
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetAlias (char* alias)
+{
+	if (alias == NULL)
+	{
+		return false;
+	}
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_GetFilename (((DIR_ENT*)globalBuffer)[wrkDirOffset], alias);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSize
+Get the file size of the last file found or openned.
+This idea is based on a modification by MoonLight
+u32 return OUT: the file size
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSize (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].fileSize;
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileCluster
+Get the first cluster of the last file found or openned.
+u32 return OUT: the file start cluster
+-----------------------------------------------------------------*/
+u32 FAT_GetFileCluster (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	(((DIR_ENT*)globalBuffer)[wrkDirOffset].startCluster) | (((DIR_ENT*)globalBuffer)[wrkDirOffset].startClusterHigh << 16);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileAttributes
+Get the attributes of the last file found or openned.
+u8 return OUT: the file's attributes
+-----------------------------------------------------------------*/
+u8 FAT_GetFileAttributes (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_SetFileAttributes
+Set the attributes of a file.
+const char* filename IN: The name and path of the file to modify
+u8 attributes IN: The attribute values to assign
+u8 mask IN: Detemines which attributes are changed
+u8 return OUT: the file's new attributes
+-----------------------------------------------------------------*/
+u8 FAT_SetFileAttributes (const char* filename, u8 attributes, u8 mask)
+{
+	// Get the file
+	if (!FAT_FileExists(filename)) {
+		return 0xff;
+	}
+
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+
+	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib = (((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib & ~(mask & 0x27)) | (attributes & 0x27);	// 0x27 is he settable attributes
+	
+	disc_WriteSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+
+	return 	((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib;
+}
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+time_t FAT_FileTimeToCTime (u16 fileTime, u16 fileDate)
+{
+	struct tm timeInfo;
+	
+	timeInfo.tm_year = (fileDate >> 9) + 80;		// years since midnight January 1970
+	timeInfo.tm_mon = ((fileDate >> 5) & 0xf) - 1;	// Months since january
+	timeInfo.tm_mday = fileDate & 0x1f;				// Day of the month
+
+	timeInfo.tm_hour = fileTime >> 11;				// hours past midnight
+	timeInfo.tm_min = (fileTime >> 5) & 0x3f;		// minutes past the hour
+	timeInfo.tm_sec = (fileTime & 0x1f) * 2;		// seconds past the minute
+
+	return mktime(&timeInfo);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileCreationTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileCreationTime (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].cTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].cDate);
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileLastWriteTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileLastWriteTime (void)
+{
+	// Read in the last accessed directory entry
+	disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer);
+	
+	return 	FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].mTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].mDate);
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_DirEntFromPath
+Finds the directory entry for a file or directory from a path
+Path separator is a forward slash /
+const char* path: IN null terminated string of path.
+DIR_ENT return OUT: dirEntry of found file. First char will be FILE_FREE
+	if the file was not found
+-----------------------------------------------------------------*/
+DIR_ENT FAT_DirEntFromPath (const char* path)
+{
+	int pathPos;
+	char name[MAX_FILENAME_LENGTH];
+	char alias[13];
+	int namePos;
+	bool found, notFound;
+	DIR_ENT dirEntry;
+	u32 dirCluster;
+	bool flagLFN, dotSeen;
+	
+	// Start at beginning of path
+	pathPos = 0;
+	
+	if (path[pathPos] == '/') 
+	{
+		dirCluster = filesysRootDirClus;	// Start at root directory
+	}
+	else
+	{
+		dirCluster = curWorkDirCluster;	// Start at current working dir
+	}
+	
+	// Eat any slash /
+	while ((path[pathPos] == '/') && (path[pathPos] != '\0'))
+	{
+		pathPos++;
+	}
+	
+	// Search until can't continue
+	found = false;
+	notFound = false;
+	while (!notFound && !found)
+	{
+		flagLFN = false;
+		// Copy name from path
+		namePos = 0;
+		if ((path[pathPos] == '.') && ((path[pathPos + 1] == '\0') || (path[pathPos + 1] == '/'))) {
+			// Dot entry
+			name[namePos++] = '.';
+			pathPos++;
+		} else if ((path[pathPos] == '.') && (path[pathPos + 1] == '.') && ((path[pathPos + 2] == '\0') || (path[pathPos + 2] == '/'))){
+			// Double dot entry
+			name[namePos++] = '.';
+			pathPos++;
+			name[namePos++] = '.';
+			pathPos++;
+		} else {
+			// Copy name from path
+			if (path[pathPos] == '.') {
+				flagLFN = true;
+			}
+			dotSeen = false;
+			while ((namePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0') && (path[pathPos] != '/'))
+			{
+				name[namePos] = ucase(path[pathPos]);
+				if ((name[namePos] <= ' ') || ((name[namePos] >= ':') && (name[namePos] <= '?'))) // Invalid character
+				{
+					flagLFN = true;
+				}
+				if (name[namePos] == '.') {
+					if (!dotSeen) {
+						dotSeen = true;
+					} else {
+						flagLFN = true;
+					}
+				}
+				namePos++;
+				pathPos++;
+			}
+			// Check if a long filename was specified
+			if (namePos > 12)
+			{
+				flagLFN = true;
+			}
+		}
+		
+		// Add end of string char
+		name[namePos] = '\0';
+
+		// Move through path to correct place
+		while ((path[pathPos] != '/') && (path[pathPos] != '\0'))
+			pathPos++;
+		// Eat any slash /
+		while ((path[pathPos] == '/') && (path[pathPos] != '\0'))
+		{
+			pathPos++;
+		}
+
+		// Search current Dir for correct entry
+		dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_SET);
+		while ( !found && !notFound)
+		{
+			// Match filename
+			found = true;
+			for (namePos = 0; (namePos < MAX_FILENAME_LENGTH) && found && (name[namePos] != '\0') && (lfnName[namePos] != '\0'); namePos++)
+			{
+				if (name[namePos] != ucase(lfnName[namePos]))
+				{
+					found = false;
+				}
+			}
+			if ((name[namePos] == '\0') != (lfnName[namePos] == '\0'))
+			{
+				found = false;
+			}
+
+			// Check against alias as well.
+			if (!found)
+			{
+				FAT_GetFilename(dirEntry, alias);
+				found = true;
+				for (namePos = 0; (namePos < 13) && found && (name[namePos] != '\0') && (alias[namePos] != '\0'); namePos++)
+				{
+					if (name[namePos] != ucase(alias[namePos]))
+					{
+						found = false;
+					}
+				}
+				if ((name[namePos] == '\0') != (alias[namePos] == '\0'))
+				{
+					found = false;
+				}
+			}
+
+			if (dirEntry.name[0] == FILE_FREE)
+				// Couldn't find specified file
+			{
+				found = false;
+				notFound = true;
+			}
+			if (!found && !notFound)
+			{
+				dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_CUR);
+			}
+		}
+		
+		if (found && ((dirEntry.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (path[pathPos] != '\0'))
+			// It has found a directory from within the path that needs to be followed
+		{
+			found = false;
+			dirCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+		}
+	}
+	
+	if (notFound)
+	{
+		dirEntry.name[0] = FILE_FREE;
+		dirEntry.attrib = 0x00;
+	}
+
+	return (dirEntry);
+}
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_AddDirEntry
+Creates a new dir entry for a file
+Path separator is a forward slash /
+const char* path: IN null terminated string of path to file.
+DIR_ENT newDirEntry IN: The directory entry to use.
+int file IN: The file being added (optional, use -1 if not used)
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry)
+{
+	char filename[MAX_FILENAME_LENGTH];
+	int filePos, pathPos, aliasPos;
+	char tempChar;
+	bool flagLFN, dotSeen;
+	char fileAlias[13] = {0};
+	int tailNum;
+	
+	unsigned char chkSum = 0;
+	
+	u32 oldWorkDirCluster;
+	
+	DIR_ENT* dirEntries = (DIR_ENT*)globalBuffer;
+	u32 dirCluster;
+	int secOffset;
+	int entryOffset;
+	int maxSectors;
+	u32 firstSector;
+
+	DIR_ENT_LFN lfnEntry;
+	int lfnPos = 0;
+
+	int dirEntryLength = 0;
+	int dirEntryRemain = 0;
+	u32 tempDirCluster;
+	int tempSecOffset;
+	int tempEntryOffset;
+	bool dirEndFlag = false;
+
+	int i;
+
+	// Store current working directory
+	oldWorkDirCluster = curWorkDirCluster;
+
+	// Find filename within path and change to correct directory
+	if (path[0] == '/')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+	}
+	
+	pathPos = 0;
+	filePos = 0;
+	flagLFN = false;
+
+	while (path[pathPos + filePos] != '\0')
+	{
+		if (path[pathPos + filePos] == '/')
+		{
+			filename[filePos] = '\0';
+			if (FAT_chdir(filename) == false) 
+			{
+				curWorkDirCluster = oldWorkDirCluster;
+				return false; // Couldn't change directory
+			}
+			pathPos += filePos + 1;
+			filePos = 0;
+		}
+		filename[filePos] = path[pathPos + filePos];
+		filePos++;
+	}
+	
+	// Skip over last slashes
+	while (path[pathPos] == '/')
+		pathPos++;
+	
+	// Check if the filename has a leading "."
+	// If so, it is an LFN
+	if (path[pathPos] == '.') {
+		flagLFN = true;
+	}
+	
+	// Copy name from path
+	filePos = 0;
+	dotSeen = false;
+
+	while ((filePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0'))
+	{
+		filename[filePos] = path[pathPos];
+		if ((filename[filePos] <= ' ') || ((filename[filePos] >= ':') && (filename[filePos] <= '?'))) // Invalid character
+		{
+			flagLFN = true;
+		}
+		if (filename[filePos] == '.') {
+			if (!dotSeen) {
+				dotSeen = true;
+			} else {
+				flagLFN = true;
+			}
+		}
+		filePos++;
+		pathPos++;
+		if ((filePos > 8) && !dotSeen) {
+			flagLFN = true;
+		}
+	}
+	
+	if (filePos == 0)	// No filename
+	{
+		return false;
+	}
+	
+	// Check if a long filename was specified
+	if (filePos > 12)
+	{
+		flagLFN = true;
+	}
+
+	// Check if extension is > 3 characters long
+	if (!flagLFN && (strrchr (filename, '.') != NULL) && (strlen(strrchr(filename, '.')) > 4)) {
+		flagLFN = true;
+	}
+	
+	lfnPos = (filePos - 1) / 13;
+
+	// Add end of string char
+	filename[filePos++] = '\0';
+	// Clear remaining chars
+	while (filePos < MAX_FILENAME_LENGTH)
+		filename[filePos++] = 0x01;	// Set for LFN compatibility
+	
+	
+	if (flagLFN)
+	{
+		// Generate short filename - always a 2 digit number for tail
+		// Get first 5 chars of alias from LFN
+		aliasPos = 0;
+		filePos = 0;
+		if (filename[filePos] == '.') {
+			filePos++;
+		}
+		for ( ; (aliasPos < 5) && (filename[filePos] != '\0') && (filename[filePos] != '.') ; filePos++)
+		{
+			tempChar = ucase(filename[filePos]);
+			if (((tempChar > ' ' && tempChar < ':') || tempChar > '?') && tempChar != '.')
+				fileAlias[aliasPos++] = tempChar;
+		}
+		// Pad Alias with underscores
+		while (aliasPos < 5)
+			fileAlias[aliasPos++] = '_';
+		
+		fileAlias[5] = '~';
+		fileAlias[8] = '.';
+		fileAlias[9] = ' ';
+		fileAlias[10] = ' ';
+		fileAlias[11] = ' ';
+		if (strchr (filename, '.') != NULL) {
+			while(filename[filePos] != '\0')
+			{
+				filePos++;
+				if (filename[filePos] == '.')
+				{
+					pathPos = filePos;
+				}
+			}
+			filePos = pathPos + 1;	//pathPos is used as a temporary variable
+			// Copy first 3 characters of extension
+			for (aliasPos = 9; (aliasPos < 12) && (filename[filePos] != '\0'); filePos++)
+			{
+				tempChar = ucase(filename[filePos]);
+				if ((tempChar > ' ' && tempChar < ':') || tempChar > '?')
+					fileAlias[aliasPos++] = tempChar;
+			}
+		} else {
+			aliasPos = 9;
+		}
+		
+		// Pad Alias extension with spaces
+		while (aliasPos < 12)
+			fileAlias[aliasPos++] = ' ';
+		
+		fileAlias[12] = '\0';
+		
+		
+		// Get a valid tail number
+		tailNum = 0;
+		do {
+			tailNum++;
+			fileAlias[6] = 0x30 + ((tailNum / 10) % 10);	// 10's digit
+			fileAlias[7] = 0x30 + (tailNum % 10);	// 1's digit
+		} while ((FAT_DirEntFromPath(fileAlias).name[0] != FILE_FREE) && (tailNum < 100));
+		
+		if (tailNum < 100)	// Found an alias not being used
+		{
+			// Calculate file checksum
+			chkSum = 0;
+			for (aliasPos=0; aliasPos < 12; aliasPos++)
+			{
+				// Skip '.'
+				if (fileAlias[aliasPos] == '.')
+					aliasPos++;
+				// NOTE: The operation is an unsigned char rotate right
+				chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + fileAlias[aliasPos];
+			}
+		}
+		else	// Couldn't find a valid alias
+		{
+			return false;
+		}
+		
+		dirEntryLength = lfnPos + 2;
+	}
+	else	// Its not a long file name
+	{
+		// Just copy alias straight from filename
+		for (aliasPos = 0; aliasPos < 13; aliasPos++)
+		{
+			tempChar = ucase(filename[aliasPos]);
+			if ((tempChar > ' ' && tempChar < ':') || tempChar > '?')
+				fileAlias[aliasPos] = tempChar;
+		}
+		fileAlias[12] = '\0';
+
+		lfnPos = -1;
+
+		dirEntryLength = 1;
+	}
+	
+	// Change dirEntry name to match alias
+	for (aliasPos = 0; ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0') && (aliasPos < 8)); aliasPos++)
+	{
+		newDirEntry.name[aliasPos] = fileAlias[aliasPos];
+	}
+	while (aliasPos < 8)
+	{
+		newDirEntry.name[aliasPos++] = ' ';
+	}
+	aliasPos = 0;
+	while ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0'))
+		aliasPos++;
+	filePos = 0;
+	while (( filePos < 3 ) && (fileAlias[aliasPos] != '\0'))
+	{
+		tempChar = fileAlias[aliasPos++];
+		if ((tempChar > ' ' && tempChar < ':' && tempChar!='.') || tempChar > '?')
+			newDirEntry.ext[filePos++] = tempChar;
+	}
+	while (filePos < 3)
+	{
+		newDirEntry.ext[filePos++] = ' ';
+	}
+
+	// Scan Dir for free entry
+	dirCluster = curWorkDirCluster;
+	secOffset = 0;
+	entryOffset = 0;
+	maxSectors = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus);
+	firstSector = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(dirCluster));
+	disc_ReadSector (firstSector + secOffset, dirEntries);
+	
+	dirEntryRemain = dirEntryLength;
+	tempDirCluster = dirCluster;
+	tempSecOffset = secOffset;
+	tempEntryOffset = entryOffset;
+		
+	// Search for a large enough space to fit in new directory entry
+	while ((dirEntries[entryOffset].name[0] != FILE_LAST) && (dirEntryRemain > 0))
+	{
+
+		entryOffset++;
+
+		if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			entryOffset = 0;
+			secOffset++;
+			if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				secOffset = 0;
+				if (FAT_NextCluster(dirCluster) == CLUSTER_EOF)
+				{
+					dirCluster = FAT_LinkFreeCluster(dirCluster);
+					dirEntries[0].name[0] = FILE_LAST;
+				}
+				else
+				{
+					dirCluster = FAT_NextCluster(dirCluster);
+				}
+				firstSector = FAT_ClustToSect(dirCluster);		
+			}
+			else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir)))
+			{
+				return false;	// Got to end of root dir - can't fit in more files
+			}
+			disc_ReadSector (firstSector + secOffset, dirEntries);
+		}
+
+		if ((dirEntries[entryOffset].name[0] == FILE_FREE) || (dirEntries[entryOffset].name[0] == FILE_LAST) )
+		{
+			dirEntryRemain--;
+		} else {
+			dirEntryRemain = dirEntryLength;
+			tempDirCluster = dirCluster;
+			tempSecOffset = secOffset;
+			tempEntryOffset = entryOffset;
+		}
+	}
+
+	// Modifying the last directory is a special case - have to erase following entries
+	if (dirEntries[entryOffset].name[0] == FILE_LAST) 
+	{
+		dirEndFlag = true;
+	}
+
+	// Recall last used entry
+	dirCluster = tempDirCluster;
+	secOffset = tempSecOffset;
+	entryOffset = tempEntryOffset;
+	dirEntryRemain = dirEntryLength;
+
+	// Re-read in first sector that will be written to
+	if (dirEndFlag && (entryOffset == 0))	{
+		memset (dirEntries, FILE_LAST, BYTE_PER_READ);
+	} else {
+		disc_ReadSector (firstSector + secOffset, dirEntries);
+	}
+
+	// Add new directory entry
+	while (dirEntryRemain > 0)	
+	{
+		// Move to next entry, first pass advances from last used entry
+		entryOffset++;
+		if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT))
+		{
+			// Write out the current sector if we need to
+			entryOffset = 0;
+			if (dirEntryRemain < dirEntryLength) // Don't write out sector on first pass
+			{
+				disc_WriteSector (firstSector + secOffset, dirEntries);
+			}
+			secOffset++;
+			if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER))
+			{
+				secOffset = 0;
+				if (FAT_NextCluster(dirCluster) == CLUSTER_EOF)
+				{
+					dirCluster = FAT_LinkFreeCluster(dirCluster);
+					dirEntries[0].name[0] = FILE_LAST;
+				}
+				else
+				{
+					dirCluster = FAT_NextCluster(dirCluster);
+				}
+				firstSector = FAT_ClustToSect(dirCluster);		
+			}
+			else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir)))
+			{
+				return false;	// Got to end of root dir - can't fit in more files
+			}
+			if (dirEndFlag)
+			{
+				memset (dirEntries, FILE_LAST, BYTE_PER_READ);
+			} else {
+				disc_ReadSector (firstSector + secOffset, dirEntries);
+			}
+		}
+
+		// Generate LFN entries
+		if (lfnPos >= 0)
+		{
+			lfnEntry.ordinal = (lfnPos + 1) | (dirEntryRemain == dirEntryLength ? LFN_END : 0);
+			for (i = 0; i < 13; i++) {
+				if (filename [lfnPos * 13 + i] == 0x01) {
+					((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = 0xff;
+					((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0xff;
+				} else {
+					((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = filename [lfnPos * 13 + i];
+					((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0x00;
+				}
+			}
+
+			lfnEntry.checkSum = chkSum;
+			lfnEntry.flag = ATTRIB_LFN;
+			lfnEntry.reserved1 = 0;
+			lfnEntry.reserved2 = 0;
+			
+			*((DIR_ENT_LFN*)&dirEntries[entryOffset]) = lfnEntry;
+			lfnPos --;
+			lfnEntry.ordinal = 0;
+		}	// end writing long filename entries
+		else
+		{
+			dirEntries[entryOffset] = newDirEntry;
+			if (dirEndFlag && (entryOffset < (BYTE_PER_READ / sizeof (DIR_ENT))) )
+				dirEntries[entryOffset+1].name[0] = FILE_LAST;
+		}
+
+		dirEntryRemain--;
+	}
+	
+	// Write directory back to disk
+	disc_WriteSector (firstSector + secOffset, dirEntries);
+
+	// Change back to Working DIR
+	curWorkDirCluster = oldWorkDirCluster;
+
+	return true;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_FindNextFile
+Gets the name of the next directory entry
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFile(char* filename)
+{
+	// Get the next directory entry
+	DIR_ENT file;
+	file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_CUR);
+
+	if (file.name[0] == FILE_FREE)
+	{
+		return FT_NONE;	// Did not find a file
+	}
+
+	// Get the filename
+	if (filename != NULL)
+		FAT_GetFilename (file, filename);
+
+	if ((file.attrib & ATTRIB_DIR) != 0)
+	{
+		return FT_DIR;	// Found a directory
+	}
+	else
+	{
+		return FT_FILE;	// Found a file
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFile
+Gets the name of the first directory entry and resets the count
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFile(char* filename)
+{
+	// Get the first directory entry
+	DIR_ENT file;
+	file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_SET);
+	
+	if (file.name[0] == FILE_FREE)
+	{
+		return FT_NONE;	// Did not find a file
+	}
+
+	// Get the filename
+	if (filename != NULL)
+		FAT_GetFilename (file, filename);
+
+	if ((file.attrib & ATTRIB_DIR) != 0)
+	{
+		return FT_DIR;	// Found a directory
+	}
+	else
+	{
+		return FT_FILE;	// Found a file
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFileLFN
+Gets the long file name of the first directory entry and resets
+	the count (can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFileLFN(char* lfn)
+{
+	FILE_TYPE type;
+	type = FAT_FindFirstFile(NULL);
+	FAT_GetLongFilename (lfn);
+	return type;
+}
+
+/*-----------------------------------------------------------------
+FAT_FindNextFileLFN
+Gets the long file name of the next directory entry
+	(can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFileLFN(char* lfn)
+{
+	FILE_TYPE type;
+	type = FAT_FindNextFile(NULL);
+	FAT_GetLongFilename (lfn);
+	return type;
+}
+
+
+/*-----------------------------------------------------------------
+FAT_FileExists
+Returns the type of file 
+char* filename: IN filename of the file to look for
+FILE_TYPE return: OUT returns FT_NONE if there is now file with 
+	that name, FT_FILE if it is a file and FT_DIR if it is a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FileExists(const char* filename)
+{
+    DIR_ENT dirEntry; 
+    // Get the dirEntry for the path specified 
+    dirEntry = FAT_DirEntFromPath (filename); 
+
+    if (dirEntry.name[0] == FILE_FREE) 
+    { 
+        return FT_NONE; 
+    } 
+    else if (dirEntry.attrib & ATTRIB_DIR) 
+    { 
+        return FT_DIR; 
+    } 
+    else 
+    { 
+         return FT_FILE; 
+    } 
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemType
+FS_TYPE return: OUT returns the current file system type
+-----------------------------------------------------------------*/
+FS_TYPE FAT_GetFileSystemType (void)
+{
+	return filesysType;
+}
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemTotalSize
+u32 return: OUT returns the total disk space (used + free)
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSystemTotalSize (void)
+{
+	return filesysTotalSize;
+}
+
+
+
+/*-----------------------------------------------------------------
+FAT_chdir
+Changes the current working directory
+const char* path: IN null terminated string of directory separated by 
+	forward slashes, / is root
+bool return: OUT returns true if successful
+-----------------------------------------------------------------*/
+bool FAT_chdir (const char* path)
+{
+	DIR_ENT dir;
+	if (path[0] == '/' && path[1] == '\0')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+		return true;
+	}
+	if (path[0] == '\0')	// Return true if changing relative to nothing
+	{
+		return true;
+	}
+	
+	dir = FAT_DirEntFromPath (path);
+
+	if (((dir.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (dir.name[0] != FILE_FREE))
+	{
+		// Change directory
+		curWorkDirCluster = dir.startCluster | (dir.startClusterHigh << 16);
+
+		// Move to correct cluster for root directory
+		if (curWorkDirCluster == FAT16_ROOT_DIR_CLUSTER)
+		{
+			curWorkDirCluster = filesysRootDirClus;
+		}
+
+		// Reset file position in directory
+		wrkDirCluster = curWorkDirCluster;
+		wrkDirSector = 0;
+		wrkDirOffset = -1;
+		return true;
+	}
+	else
+	{ 
+		// Couldn't change directory - wrong path specified
+		return false;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_fopen(filename, mode)
+Opens a file
+const char* path: IN null terminated string of filename and path 
+	separated by forward slashes, / is root
+const char* mode: IN mode to open file in
+	Supported modes: "r", "r+", "w", "w+", "a", "a+", don't use
+	"b" or "t" in any mode, as all files are openned in binary mode
+FAT_FILE* return: OUT handle to open file, returns NULL if the file 
+	couldn't be openned
+-----------------------------------------------------------------*/
+FAT_FILE* FAT_fopen(const char* path, const char* mode)
+{
+	int fileNum;
+	FAT_FILE* file;
+	DIR_ENT dirEntry;
+#ifdef CAN_WRITE_TO_DISC
+	u32 startCluster;
+	int clusCount;
+#endif
+
+	char* pchTemp;
+	// Check that a valid mode was specified
+	pchTemp = strpbrk ( mode, "rRwWaA" );
+	if (pchTemp == NULL)
+	{
+		return NULL;
+	}
+	if (strpbrk ( pchTemp+1, "rRwWaA" ) != NULL)
+	{
+		return NULL;
+	}
+		
+	// Get the dirEntry for the path specified
+	dirEntry = FAT_DirEntFromPath (path);
+	
+	// Check that it is not a directory
+	if (dirEntry.attrib & ATTRIB_DIR)
+	{
+		return NULL;
+	}
+
+#ifdef CAN_WRITE_TO_DISC
+	// Check that it is not a read only file being openned in a writing mode
+	if ( (strpbrk(mode, "wWaA+") != NULL) && (dirEntry.attrib & ATTRIB_RO))
+	{
+		return NULL;
+	}
+#else
+	if ( (strpbrk(mode, "wWaA+") != NULL))
+	{
+		return NULL;
+	}
+#endif
+
+	// Find a free file buffer
+	for (fileNum = 0; (fileNum < MAX_FILES_OPEN) && (openFiles[fileNum].inUse == true); fileNum++);
+	
+	if (fileNum == MAX_FILES_OPEN) // No free files
+	{
+		return NULL;
+	}
+
+	file = &openFiles[fileNum];
+	// Remember where directory entry was
+	file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+	file->dirEntOffset = wrkDirOffset;
+
+	if ( strpbrk(mode, "rR") != NULL )  //(ucase(mode[0]) == 'R')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// File must exist
+		{
+			return NULL;
+		}
+		
+		file->read = true;
+#ifdef CAN_WRITE_TO_DISC
+		file->write = ( strchr(mode, '+') != NULL ); //(mode[1] == '+');
+#else
+		file->write = false;
+#endif
+		file->append = false;
+		
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+	
+#ifdef CAN_WRITE_TO_DISC
+		// Check if file is openned for random. If it is, and currently has no cluster, one must be 
+		// assigned to it.
+		if (file->write && file->firstCluster == CLUSTER_FREE)
+		{
+			file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+			if (file->firstCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+			{
+				return NULL;
+			}
+
+			// Store cluster position into the directory entry
+			dirEntry.startCluster = (file->firstCluster & 0xFFFF);
+			dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF);
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+			((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+		}
+#endif
+			
+		file->length = dirEntry.fileSize;
+		file->curPos = 0;
+		file->curClus = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+		file->curSect = 0;
+		file->curByte = 0;
+
+		// Not appending
+		file->appByte = 0;
+		file->appClus = 0;
+		file->appSect = 0;
+	
+		disc_ReadSector( FAT_ClustToSect( file->curClus), file->readBuffer);
+		file->inUse = true;	// We're using this file now
+
+		return file;
+	}	// mode "r"
+
+#ifdef CAN_WRITE_TO_DISC
+	if ( strpbrk(mode, "wW") != NULL ) // (ucase(mode[0]) == 'W')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// Create file if it doesn't exist
+		{
+			dirEntry.attrib = ATTRIB_ARCH;
+			dirEntry.reserved = 0;
+			
+			// Time and date set to system time and date
+			dirEntry.cTime_ms = 0;
+			dirEntry.cTime = getRTCtoFileTime();
+			dirEntry.cDate = getRTCtoFileDate();
+			dirEntry.aDate = getRTCtoFileDate();
+			dirEntry.mTime = getRTCtoFileTime();
+			dirEntry.mDate = getRTCtoFileDate();
+		}
+		else	// Already a file entry 
+		{
+			// Free any clusters used
+			FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16));
+		}
+		
+		// Get a cluster to use
+		startCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+		if (startCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+		{
+			return NULL;
+		}
+
+		// Store cluster position into the directory entry
+		dirEntry.startCluster = (startCluster & 0xFFFF);
+		dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF);
+
+		// The file has no data in it - its over written so should be empty
+		dirEntry.fileSize = 0;
+
+		if (dirEntry.name[0] == FILE_FREE)	// No file
+		{
+			// Have to create a new entry
+			if(!FAT_AddDirEntry (path, dirEntry))
+			{
+				return NULL;
+			}
+			// Get the newly created dirEntry
+			dirEntry = FAT_DirEntFromPath (path);
+
+			// Remember where directory entry was
+			file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+			file->dirEntOffset = wrkDirOffset;
+		}
+		else	// Already a file
+		{
+			// Just modify the old entry
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+			((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+		}
+		
+
+		// Now that file is created, open it
+		file->read = ( strchr(mode, '+') != NULL ); //(mode[1] == '+');
+		file->write = true;
+		file->append = false;
+		
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = startCluster;
+		file->length = 0;	// Should always have 0 bytes if openning in "w" mode
+		file->curPos = 0;
+		file->curClus = startCluster;
+		file->curSect = 0;
+		file->curByte = 0;
+
+		// Not appending
+		file->appByte = 0;
+		file->appClus = 0;
+		file->appSect = 0;
+		
+		// Empty file, so empty read buffer
+		memset (file->readBuffer, 0, BYTE_PER_READ);
+		file->inUse = true;	// We're using this file now
+
+		return file;
+	}
+
+	if ( strpbrk(mode, "aA") != NULL ) // (ucase(mode[0]) == 'A')
+	{
+		if (dirEntry.name[0] == FILE_FREE)	// Create file if it doesn't exist
+		{
+			dirEntry.attrib = ATTRIB_ARCH;
+			dirEntry.reserved = 0;
+			
+			// Time and date set to system time and date
+			dirEntry.cTime_ms = 0;
+			dirEntry.cTime = getRTCtoFileTime();
+			dirEntry.cDate = getRTCtoFileDate();
+			dirEntry.aDate = getRTCtoFileDate();
+			dirEntry.mTime = getRTCtoFileTime();
+			dirEntry.mDate = getRTCtoFileDate();
+
+			// The file has no data in it
+			dirEntry.fileSize = 0;
+
+			// Get a cluster to use
+			startCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+			if (startCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+			{
+				return NULL;
+			}
+			dirEntry.startCluster = (startCluster & 0xFFFF);
+			dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF);
+			
+			if(!FAT_AddDirEntry (path, dirEntry))
+				return NULL;
+			
+			// Get the newly created dirEntry
+			dirEntry = FAT_DirEntFromPath (path);
+			
+			// Store append cluster
+			file->appClus = startCluster;
+
+			// Remember where directory entry was
+			file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector;
+			file->dirEntOffset = wrkDirOffset;
+		}
+		else	// File already exists - reuse the old directory entry
+		{
+			startCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16);
+			// If it currently has no cluster, one must be assigned to it.
+			if (startCluster == CLUSTER_FREE)
+			{
+				file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE);
+				if (file->firstCluster == CLUSTER_FREE)	// Couldn't get a free cluster
+				{
+					return NULL;
+				}
+				
+				// Store cluster position into the directory entry
+				dirEntry.startCluster = (file->firstCluster & 0xFFFF);
+				dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF);
+				disc_ReadSector (file->dirEntSector, globalBuffer);
+				((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry;
+				disc_WriteSector (file->dirEntSector, globalBuffer);
+
+				// Store append cluster
+				file->appClus = startCluster;
+		
+			} else {
+
+				// Follow cluster list until last one is found
+				clusCount = dirEntry.fileSize / filesysBytePerClus;
+				file->appClus = startCluster;
+				while ((clusCount--) && (FAT_NextCluster (file->appClus) != CLUSTER_FREE) && (FAT_NextCluster (file->appClus) != CLUSTER_EOF))
+				{
+					file->appClus = FAT_NextCluster (file->appClus);
+				}
+				if (clusCount >= 0) // Check if ran out of clusters
+				{
+					// Set flag to allocate new cluster when needed
+					file->appSect = filesysSecPerClus;
+					file->appByte = 0;
+				}
+			}
+		}
+
+		// Now that file is created, open it
+		file->read = ( strchr(mode, '+') != NULL );
+		file->write = false;
+		file->append = true;
+		
+		// Calculate the sector and byte of the current position,
+		// and store them
+		file->appSect = (dirEntry.fileSize % filesysBytePerClus) / BYTE_PER_READ;
+		file->appByte = dirEntry.fileSize % BYTE_PER_READ;
+
+		// Store information about position within the file, for use
+		// by FAT_fread, FAT_fseek, etc.
+		file->firstCluster = startCluster;
+		file->length = dirEntry.fileSize;
+		file->curPos = dirEntry.fileSize;
+		file->curClus = file->appClus;
+		file->curSect = file->appSect;
+		file->curByte = file->appByte;
+		
+		// Read into buffer
+		disc_ReadSector( FAT_ClustToSect(file->curClus) + file->curSect, file->readBuffer);
+		file->inUse = true;	// We're using this file now
+		return file;
+	}
+#endif
+
+	// Can only reach here if a bad mode was specified
+	return NULL;
+}
+
+/*-----------------------------------------------------------------
+FAT_fclose(file)
+Closes a file
+FAT_FILE* file: IN handle of the file to close
+bool return OUT: true if successful, false if not
+-----------------------------------------------------------------*/
+bool FAT_fclose (FAT_FILE* file)
+{
+	// Clear memory used by file information
+	if ((file != NULL) && (file->inUse == true))
+	{
+#ifdef CAN_WRITE_TO_DISC
+		if (file->write || file->append)
+		{
+			// Write new length, time and date back to directory entry
+			disc_ReadSector (file->dirEntSector, globalBuffer);
+
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].fileSize = file->length;
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].mTime = getRTCtoFileTime();
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].mDate = getRTCtoFileDate();
+			((DIR_ENT*)globalBuffer)[file->dirEntOffset].aDate = getRTCtoFileDate();
+
+			disc_WriteSector (file->dirEntSector, globalBuffer);
+
+			// Flush any sectors in disc cache
+			disc_CacheFlush();
+		}
+#endif
+		file->inUse = false;		
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_ftell(file)
+Returns the current position in a file
+FAT_FILE* file: IN handle of an open file
+u32 OUT: Current position
+-----------------------------------------------------------------*/
+u32 FAT_ftell (FAT_FILE* file)
+{
+	// Return the position as specified in the FAT_FILE structure
+	if ((file != NULL) && (file->inUse == true))
+	{
+		return file->curPos;
+	}
+	else
+	{
+		// Return -1 if no file was given
+		return -1;
+	}
+}
+
+/*-----------------------------------------------------------------
+FAT_fseek(file, offset, origin)
+Seeks to specified byte position in file
+FAT_FILE* file: IN handle of an open file
+s32 offset IN: position to seek to, relative to origin
+int origin IN: origin to seek from
+int OUT: Returns 0 if successful, -1 if not
+-----------------------------------------------------------------*/
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin)
+{
+	u32 cluster, nextCluster;
+	int clusCount;
+	u32 position;
+	u32 curPos;
+
+	if ((file == NULL) || (file->inUse == false))	// invalid file
+	{
+		return -1;
+	}
+
+	// Can't seek in append only mode
+	if (!file->read && !file->write)	
+	{
+		return -1;
+	}
+
+	curPos = file->curPos;
+
+	switch (origin) 
+	{
+	case SEEK_SET:
+		if (offset >= 0)
+		{
+			position = offset;
+		} else {
+			// Tried to seek before start of file
+			position = 0;
+		}
+		break;
+	case SEEK_CUR:
+		if (offset >= 0)
+		{
+			position = curPos + offset;
+		} 
+		else if ( (u32)(offset * -1) >= curPos )
+		{
+			// Tried to seek before start of file
+			position = 0;
+		}
+		else 
+		{
+			// Using u32 to maintain 32 bits of accuracy
+			position = curPos - (u32)(offset * -1);
+		}
+		break;
+	case SEEK_END:
+		if (offset >= 0)
+		{
+			// Seeking to end of file
+			position = file->length;	// Fixed thanks to MoonLight
+		}
+		else if ( (u32)(offset * -1) >= file->length )
+		{
+			// Tried to seek before start of file
+			position = 0;
+		}
+		else 
+		{
+			// Using u32 to maintain 32 bits of accuracy
+			position = file->length - (u32)(offset * -1);
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	if (position > file->length)
+	{
+		// Tried to go past end of file
+		position = file->length;
+	}
+	
+	// Save position
+	file->curPos = position;
+
+
+	// Calculate where the correct cluster is
+	if (position > curPos)
+	{
+		clusCount = (position - curPos + (file->curSect * filesysBytePerSec) + file->curByte) / filesysBytePerClus;	// Fixed thanks to AgentQ
+		cluster = file->curClus;
+	} else {
+		clusCount = position / filesysBytePerClus;
+		cluster = file->firstCluster;
+	}
+
+	// Calculate the sector and byte of the current position,
+	// and store them
+	file->curSect = (position % filesysBytePerClus) / BYTE_PER_READ;
+	file->curByte = position % BYTE_PER_READ;
+
+	// Follow cluster list until desired one is found
+	if (clusCount > 0)	// Only look at next cluster if need to
+	{
+		nextCluster = FAT_NextCluster (cluster);
+	} else {
+		nextCluster = cluster;
+	}
+	while ((clusCount--) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF))
+	{
+		cluster = nextCluster;
+		nextCluster = FAT_NextCluster (cluster);
+	}
+	// Check if ran out of clusters, and the file is being written to
+	if ((clusCount >= 0) && (file->write || file->append)) 
+	{
+		// Set flag to allocate a new cluster
+		file->curSect = filesysSecPerClus;
+		file->curByte = 0;
+	}
+	file->curClus = cluster;
+	
+	// Reload sector buffer for new position in file, if it is a different sector
+	if ((curPos ^ position) >= BYTE_PER_READ)
+	{
+		disc_ReadSector( file->curSect + FAT_ClustToSect(file->curClus), file->readBuffer);
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+FAT_fread(buffer, size, count, file)
+Reads in size * count bytes into buffer from file, starting
+	from current position. It then sets the current position to the
+	byte after the last byte read. If it reaches the end of file
+	before filling the buffer then it stops reading.
+void* buffer OUT: Pointer to buffer to fill. Should be at least as
+	big as the number of bytes required
+u32 size IN: size of each item to read
+u32 count IN: number of items to read
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes read
+-----------------------------------------------------------------*/
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file)
+{
+	int curByte;
+	int curSect;
+	u32 curClus;
+	u32 tempNextCluster;
+	
+	int tempVar;
+
+	char* data = (char*)buffer;
+
+	u32 length = size * count;
+	u32 remain;
+
+	bool flagNoError = true;
+
+	// Can't read non-existant files
+	if ((file == NULL) || (file->inUse == false) || size == 0 || count == 0 || buffer == NULL)
+		return 0;
+
+	// Can only read files openned for reading
+	if (!file->read)
+		return 0;
+
+	// Don't read past end of file
+	if (length + file->curPos > file->length)
+		length = file->length - file->curPos;
+
+	remain = length;
+
+	curByte = file->curByte;
+	curSect = file->curSect;
+	curClus = file->curClus;
+
+	// Align to sector
+	tempVar = BYTE_PER_READ - curByte;
+	if (tempVar > remain)
+		tempVar = remain;
+
+	if ((tempVar < BYTE_PER_READ) && flagNoError) 
+	{
+		memcpy(data, &(file->readBuffer[curByte]), tempVar);
+		remain -= tempVar;
+		data += tempVar;
+
+		curByte += tempVar;
+		if (curByte >= BYTE_PER_READ) 
+		{
+			curByte = 0;
+			curSect++;
+		}
+	}
+
+	// align to cluster
+	// tempVar is number of sectors to read
+	if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) 
+	{
+		tempVar = filesysSecPerClus - curSect;
+	} else {
+		tempVar = remain / BYTE_PER_READ;
+	}
+
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_ReadSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+
+		curSect += tempVar;
+	}
+
+	// Move onto next cluster
+	// It should get to here without reading anything if a cluster is due to be allocated
+	if (curSect >= filesysSecPerClus)
+	{
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((remain == 0) && (tempNextCluster == CLUSTER_EOF))
+		{
+			curSect = filesysSecPerClus;
+		} else {
+			curSect = 0;
+			curClus = tempNextCluster;
+			if (curClus == CLUSTER_FREE)
+			{
+				flagNoError = false;
+			}
+		}
+	}
+
+	// Read in whole clusters
+	while ((remain >= filesysBytePerClus) && flagNoError)
+	{
+		disc_ReadSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data);
+		data += filesysBytePerClus;
+		remain -= filesysBytePerClus;
+
+		// Advance to next cluster
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((remain == 0) && (tempNextCluster == CLUSTER_EOF))
+		{
+			curSect = filesysSecPerClus;
+		} else {
+			curSect = 0;
+			curClus = tempNextCluster;
+			if (curClus == CLUSTER_FREE)
+			{
+				flagNoError = false;
+			}
+		}
+	}
+
+	// Read remaining sectors
+	tempVar = remain / BYTE_PER_READ; // Number of sectors left
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_ReadSectors (FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+
+	// Last remaining sector
+	// Check if sector wanted is different to the one started with
+	if ( ((file->curByte + length) >= BYTE_PER_READ) && flagNoError)
+	{
+		disc_ReadSector( curSect + FAT_ClustToSect( curClus), file->readBuffer);
+		if (remain > 0)
+		{
+			memcpy(data, file->readBuffer, remain);
+			curByte += remain;
+			remain = 0;
+		}
+	}
+
+	// Length read is the wanted length minus the stuff not read
+	length = length - remain;
+
+	// Update file information
+	file->curByte = curByte;
+	file->curSect = curSect;
+	file->curClus = curClus;
+	file->curPos = file->curPos + length;
+	return length;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fwrite(buffer, size, count, file)
+Writes size * count bytes into file from buffer, starting
+	from current position. It then sets the current position to the
+	byte after the last byte written. If the file was openned in 
+	append mode it always writes to the end of the file.
+const void* buffer IN: Pointer to buffer containing data. Should be
+	at least as big as the number of bytes to be written.
+u32 size IN: size of each item to write
+u32 count IN: number of items to write
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes written
+-----------------------------------------------------------------*/
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file)
+{
+	int curByte;
+	int curSect;
+	u32 curClus;
+
+	u32 tempNextCluster;
+	int tempVar;
+	u32 length = size * count;
+	u32 remain = length;
+	char* data = (char*)buffer;
+
+	char* writeBuffer;
+
+	bool flagNoError = true;
+	bool flagAppending = false;
+
+	if ((file == NULL) || (file->inUse == false) || length == 0 || buffer == NULL)
+		return 0;
+
+	if (file->write)
+	{
+		// Write at current read pointer
+		curByte = file->curByte;
+		curSect = file->curSect;
+		curClus = file->curClus;
+
+		// Use read buffer as write buffer
+		writeBuffer = file->readBuffer;
+
+		// If it is writing past the current end of file, set appending flag
+		if (length + file->curPos > file->length)
+		{
+			flagAppending = true;
+		}
+	}
+	else if (file->append)
+	{
+		// Write at end of file
+		curByte = file->appByte;
+		curSect = file->appSect;
+		curClus = file->appClus;
+		flagAppending = true;
+
+		// Use global buffer as write buffer, don't touch read buffer
+		writeBuffer = (char*)globalBuffer;
+		disc_ReadSector(curSect + FAT_ClustToSect(curClus), writeBuffer);
+	}
+	else
+	{
+		return 0;
+	}
+
+	// Move onto next cluster if needed
+	if (curSect >= filesysSecPerClus)
+	{
+		curSect = 0;
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+		{
+			// Ran out of clusters so get a new one
+			curClus = FAT_LinkFreeCluster(curClus);
+			if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+			{
+				flagNoError = false;
+			}
+			memset(writeBuffer, 0, BYTE_PER_READ);
+		} else {
+			curClus = tempNextCluster;
+			disc_ReadSector( FAT_ClustToSect( curClus), writeBuffer);
+		}
+	}
+	
+	// Align to sector
+	tempVar = BYTE_PER_READ - curByte;
+	if (tempVar > remain)
+		tempVar = remain;
+
+	if ((tempVar < BYTE_PER_READ) && flagNoError)
+	{
+		memcpy(&(writeBuffer[curByte]), data, tempVar);
+		remain -= tempVar;
+		data += tempVar;
+		curByte += tempVar;
+
+		// Write buffer back to disk
+		disc_WriteSector (curSect + FAT_ClustToSect(curClus), writeBuffer);
+		
+		// Move onto next sector
+		if (curByte >= BYTE_PER_READ) 
+		{
+			curByte = 0;
+			curSect++;
+		}
+	}
+
+	// Align to cluster
+	// tempVar is number of sectors to write
+	if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) 
+	{
+		tempVar = filesysSecPerClus - curSect;
+	} else {
+		tempVar = remain / BYTE_PER_READ;
+	}
+
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_WriteSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+
+	if (((curSect >= filesysSecPerClus) && flagNoError) && (remain > 0))
+	{
+		curSect = 0;
+		tempNextCluster = FAT_NextCluster(curClus);
+		if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+		{
+			// Ran out of clusters so get a new one
+			curClus = FAT_LinkFreeCluster(curClus);
+			if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+			{
+				flagNoError = false;
+			}
+		} else {
+			curClus = tempNextCluster;
+		}
+	}
+
+	// Write whole clusters
+	while ((remain >= filesysBytePerClus) && flagNoError)
+	{
+		disc_WriteSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data);
+		data += filesysBytePerClus;
+		remain -= filesysBytePerClus;
+		if (remain > 0)
+		{
+			tempNextCluster = FAT_NextCluster(curClus);
+			if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE))
+			{
+				// Ran out of clusters so get a new one
+				curClus = FAT_LinkFreeCluster(curClus);
+				if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort
+				{
+					flagNoError = false;
+					break;
+				}
+			} else {
+				curClus = tempNextCluster;
+			}
+		} else {
+			// Allocate a new cluster when next writing the file
+			curSect = filesysSecPerClus;
+		}
+	}
+
+	// Write remaining sectors
+	tempVar = remain / BYTE_PER_READ; // Number of sectors left
+	if ((tempVar > 0) && flagNoError)
+	{
+		disc_WriteSectors (FAT_ClustToSect(curClus), tempVar, data);
+		data += tempVar * BYTE_PER_READ;
+		remain -= tempVar * BYTE_PER_READ;
+		curSect += tempVar;
+	}
+	
+	// Last remaining sector
+	// Check if sector wanted is different to the one started with
+	if ( (( (file->append ? file->appByte : file->curByte) + length) >= BYTE_PER_READ) && flagNoError)
+	{
+		if (flagAppending)
+		{
+			// Zero sector before using it
+			memset (writeBuffer, 0, BYTE_PER_READ);
+		} else {
+			// Modify existing sector
+			disc_ReadSector( curSect + FAT_ClustToSect( curClus), writeBuffer);
+		}
+		if (remain > 0) {
+			memcpy(writeBuffer, data, remain);
+			curByte += remain;
+			remain = 0;
+			disc_WriteSector( curSect + FAT_ClustToSect( curClus), writeBuffer);
+		}
+	}
+	
+	// Amount read is the originally requested amount minus stuff remaining
+	length = length - remain;
+
+	// Update file information
+	if (file->write)	// Writing also shifts the read pointer
+	{
+		file->curByte = curByte;
+		file->curSect = curSect;
+		file->curClus = curClus;
+		file->curPos = file->curPos + length;
+		if (file->length < file->curPos)
+		{
+			file->length = file->curPos;
+		}
+	}
+	else if (file->append)	// Appending doesn't affect the read pointer
+	{
+		file->appByte = curByte;
+		file->appSect = curSect;
+		file->appClus = curClus;
+		file->length = file->length + length;
+	}
+
+	return length;
+}
+#endif
+
+
+/*-----------------------------------------------------------------
+FAT_feof(file)
+Returns true if the end of file has been reached
+FAT_FILE* file IN: Handle of an open file
+bool return OUT: true if EOF, false if not
+-----------------------------------------------------------------*/
+bool FAT_feof(FAT_FILE* file)
+{
+	if ((file == NULL) || (file->inUse == false))
+		return true;	// Return eof on invalid files
+
+	return (file->length == file->curPos);
+}
+
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_remove (path)
+Deletes the file or empty directory sepecified in path
+const char* path IN: Path of item to delete
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_remove (const char* path)
+{
+	DIR_ENT dirEntry;
+	u32 oldWorkDirCluster;
+	char checkFilename[13];
+	FILE_TYPE checkFiletype;
+	
+	dirEntry = FAT_DirEntFromPath (path);
+
+	if (dirEntry.name[0] == FILE_FREE)
+	{
+		return -1;
+	}
+	
+	// Only delete directories if the directory is entry
+	if (dirEntry.attrib & ATTRIB_DIR)
+	{
+		// Change to the directory temporarily
+		oldWorkDirCluster = curWorkDirCluster;
+		FAT_chdir(path);
+
+		// Search for files or directories, excluding the . and .. entries
+		checkFiletype = FAT_FindFirstFile (checkFilename);
+		while ((checkFilename[0] == '.')  && (checkFiletype != FT_NONE))
+		{
+			checkFiletype = FAT_FindNextFile (checkFilename);
+		}
+		
+		// Change back to working directory
+		curWorkDirCluster = oldWorkDirCluster;
+		
+		// Check that the directory is empty
+		if (checkFiletype != FT_NONE)
+		{
+			// Directory isn't empty
+			return -1;
+		}
+	}
+
+	// Refresh directory information
+	dirEntry = FAT_DirEntFromPath (path);
+
+	// Free any clusters used
+	FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16));
+
+	// Remove Directory entry
+	disc_ReadSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer);
+	((DIR_ENT*)globalBuffer)[wrkDirOffset].name[0] = FILE_FREE;
+	disc_WriteSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer);
+		
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+
+	return 0;
+}
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_mkdir (path)
+Makes a new directory, so long as no other directory or file has 
+	the same name.
+const char* path IN: Path and filename of directory to make
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_mkdir (const char* path)
+{
+	u32 newDirCluster;
+	u32 parentDirCluster;
+	DIR_ENT dirEntry;
+	DIR_ENT* entries = (DIR_ENT*)globalBuffer;
+	int i;
+
+	int pathPos, filePos;
+	char pathname[MAX_FILENAME_LENGTH];
+	u32 oldDirCluster;
+
+	if (FAT_FileExists(path) != FT_NONE)
+	{
+		return -1;	// File or directory exists with that name
+	}
+
+	// Find filename within path and change to that directory
+	oldDirCluster = curWorkDirCluster;
+	if (path[0] == '/')
+	{
+		curWorkDirCluster = filesysRootDirClus;
+	}
+	
+	pathPos = 0;
+	filePos = 0;
+
+	while (path[pathPos + filePos] != '\0')
+	{
+		if (path[pathPos + filePos] == '/')
+		{
+			pathname[filePos] = '\0';
+			if (FAT_chdir(pathname) == false) 
+			{
+				curWorkDirCluster = oldDirCluster;
+				return -1; // Couldn't change directory
+			}
+			pathPos += filePos + 1;
+			filePos = 0;
+		}
+		pathname[filePos] = path[pathPos + filePos];
+		filePos++;
+	}
+
+	// Now grab the parent directory's cluster
+	parentDirCluster = curWorkDirCluster;
+	curWorkDirCluster = oldDirCluster;
+
+	// Get a new cluster for the file
+	newDirCluster = FAT_LinkFreeCluster(CLUSTER_FREE);
+
+	if (newDirCluster == CLUSTER_FREE)
+	{
+		return -1;	// Couldn't get a new cluster for the directory
+	}
+	// Fill in directory entry's information
+	dirEntry.attrib = ATTRIB_DIR;
+	dirEntry.reserved = 0;
+	// Time and date set to system time and date
+	dirEntry.cTime_ms = 0;
+	dirEntry.cTime = getRTCtoFileTime();
+	dirEntry.cDate = getRTCtoFileDate();
+	dirEntry.aDate = getRTCtoFileDate();
+	dirEntry.mTime = getRTCtoFileTime();
+	dirEntry.mDate = getRTCtoFileDate();
+	// Store cluster position into the directory entry
+	dirEntry.startCluster = (newDirCluster & 0xFFFF);
+	dirEntry.startClusterHigh = ((newDirCluster >> 16) & 0xFFFF);
+	// The file has no data in it - its over written so should be empty
+	dirEntry.fileSize = 0;
+
+	if (FAT_AddDirEntry (path, dirEntry) == false)
+	{
+		return -1;	// Couldn't add the directory entry
+	}
+
+	// Create the new directory itself
+	memset(entries, FILE_LAST, BYTE_PER_READ);
+
+	// Create . directory entry
+	dirEntry.name[0] = '.';
+	// Fill name and extension with spaces
+	for (i = 1; i < 11; i++)
+	{
+		dirEntry.name[i] = ' ';
+	}
+
+	memcpy(entries, &dirEntry, sizeof(dirEntry));
+
+	// Create .. directory entry
+	dirEntry.name[1] = '.';
+	dirEntry.startCluster = (parentDirCluster & 0xFFFF);
+	dirEntry.startClusterHigh = ((parentDirCluster >> 16) & 0xFFFF);
+
+	memcpy(&entries[1], &dirEntry, sizeof(dirEntry));
+
+	// Write entry to disc
+	disc_WriteSector(FAT_ClustToSect(newDirCluster), entries);
+
+	// Flush any sectors in disc cache
+	disc_CacheFlush();
+	return 0;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgetc (handle)
+Gets the next character in the file
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fgetc (FAT_FILE* file)
+{
+	char c;
+	return (FAT_fread(&c, 1, 1, file) == 1) ? c : EOF;
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputc (character, handle)
+Writes the given character into the file
+char c IN: Character to be written
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fputc (char c, FAT_FILE* file)
+{
+	return (FAT_fwrite(&c, 1, 1, file) == 1) ? c : EOF;
+}
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgets (char *tgtBuffer, int num, FAT_FILE* file)
+Gets a up to num bytes from file, stopping at the first
+ newline.
+
+CAUTION: does not do strictly streaming. I.e. it's 
+ reading more then needed bytes and seeking back.
+ shouldn't matter for random access 
+
+char *tgtBuffer OUT: buffer to write to
+int num IN: size of target buffer
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Added check for unix style text files
+	* Removed seek when no newline is found, since it isn't necessary
+-------------------------------------------------------------------*/
+char *FAT_fgets(char *tgtBuffer, int num, FAT_FILE* file) 
+{ 
+	u32 curPos;
+	u32 readLength;
+	char *returnChar;
+	
+	// invalid filehandle 
+	if (file == NULL)
+	{
+		return NULL ; 
+	}
+	
+	// end of file 
+	if (FAT_feof(file)==true)
+	{
+		return NULL ; 
+	}
+	
+	// save current position 
+	curPos = FAT_ftell(file); 
+	
+	// read the full buffer (max string chars is num-1 and one end of string \0 
+	readLength = FAT_fread(tgtBuffer,1,num-1,file) ; 
+	
+	// mark least possible end of string 
+	tgtBuffer[readLength] = '\0' ;    
+	
+	if (readLength==0) { 
+		// return error 
+		return NULL ; 
+	}
+	
+	// get position of first return '\r' 
+	returnChar = strchr(tgtBuffer,'\r'); 
+	
+	// if no return is found, search for a newline
+	if (returnChar == NULL)
+	{
+		returnChar = strchr(tgtBuffer,'\n');
+	}
+	
+	// Mark the return, if existant, as end of line/string 
+	if (returnChar!=NULL) { 
+		*returnChar++ = 0 ; 
+		if (*returnChar=='\n') { // catch newline too when jumping over the end 
+			// return to location after \r\n (strlen+2) 
+			FAT_fseek(file,curPos+strlen(tgtBuffer)+2,SEEK_SET) ; 
+			return tgtBuffer ; 
+		} else { 
+			// return to location after \r (strlen+1) 
+			FAT_fseek(file,curPos+strlen(tgtBuffer)+1,SEEK_SET) ; 
+			return tgtBuffer ; 
+		}
+	}
+	
+	return tgtBuffer ; 
+}
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputs (const char *string, FAT_FILE* file)
+Writes string to file, excluding end of string character
+const char *string IN: string to write
+FAT_FILE* file IN: Handle of open file
+bool return OUT: number of characters written if successful,
+	EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Uses FAT_FILE instead of int
+	* writtenBytes is now u32 instead of int
+-------------------------------------------------------------------*/
+int FAT_fputs (const char *string, FAT_FILE* file) 
+{ 
+   u32 writtenBytes;
+	// save string except end of string '\0' 
+   writtenBytes = FAT_fwrite((void *)string, 1, strlen(string), file); 
+
+   // check if we had an error 
+   if (writtenBytes != strlen(string)) 
+   { 
+      // return EOF error 
+      return EOF;
+   }
+
+   // return the charcount written 
+   return writtenBytes ; 
+}
+#endif
+
+
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,888 @@
+/*
+	gba_nds_fat.h
+	By chishm (Michael Chisholm)
+
+	Routines for reading a compact flash card
+	using the GBA Movie Player or M3.
+
+	Some FAT routines are based on those in fat.c, which
+	is part of avrlib by Pascal Stang.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+//---------------------------------------------------------------
+
+#ifndef _GBA_NDS_FAT_INCLUDED
+#define _GBA_NDS_FAT_INCLUDED
+
+//---------------------------------------------------------------
+// Customisable features
+
+// Maximum number of files open at once
+// Increase this to open more files, decrease to save memory
+#define MAX_FILES_OPEN	4
+
+// Allow file writing
+// Disable this to remove file writing support
+#define CAN_WRITE_TO_DISC
+
+// Allow file time functions
+// This adds ~ 14KB to the compiled size
+// Uncomment to enable
+// #define FILE_TIME_SUPPORT
+
+//---------------------------------------------------------------
+// Platform specific includes
+
+// When compiling for NDS, make sure NDS is defined
+#ifndef NDS
+ #if defined ARM9 || defined ARM7
+  #define NDS
+ #endif
+#endif
+
+#ifdef NDS
+ #include <nds/jtypes.h>
+#else
+ #include "gba_types.h"
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+ #include <time.h>
+#endif
+
+//---------------------------------------------------------------
+#ifdef __cplusplus
+extern "C" {
+#endif
+//---------------------------------------------------------------
+
+//---------------------------------------------------------------
+// Important constants
+
+
+#define MAX_FILENAME_LENGTH 256	// Maximum LFN length. Don't change this one
+
+// File Constants
+#ifndef EOF
+#define EOF -1
+#define SEEK_SET	0
+#define SEEK_CUR	1
+#define SEEK_END	2
+#endif
+
+// File attributes
+#define ATTRIB_ARCH	0x20			// Archive
+#define ATTRIB_DIR	0x10			// Directory
+#define ATTRIB_LFN	0x0F			// Long file name
+#define ATTRIB_VOL	0x08			// Volume
+#define ATTRIB_SYS	0x04			// System
+#define ATTRIB_HID	0x02			// Hidden
+#define ATTRIB_RO	0x01			// Read only
+
+
+// Directory Constants
+typedef enum {FT_NONE, FT_FILE, FT_DIR} FILE_TYPE;
+
+// Filesystem type
+typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
+
+// Open file information structure
+typedef struct
+{
+	u32 firstCluster;
+	u32 length;
+	u32 curPos;
+	u32 curClus;			// Current cluster to read from
+	int curSect;			// Current sector within cluster
+	int curByte;			// Current byte within sector
+	char readBuffer[512];	// Buffer used for unaligned reads
+	u32 appClus;			// Cluster to append to
+	int appSect;			// Sector within cluster for appending
+	int appByte;			// Byte within sector for appending
+	bool read;	// Can read from file
+	bool write;	// Can write to file
+	bool append;// Can append to file
+	bool inUse;	// This file is open
+	u32 dirEntSector;	// The sector where the directory entry is stored
+	int dirEntOffset;	// The offset within the directory sector
+}	FAT_FILE;
+
+
+//-----------------------------------------------------------------
+// CF Card functions
+
+/*-----------------------------------------------------------------
+FAT_InitFiles
+Reads the FAT information from the CF card.
+You need to call this before reading any files.
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_InitFiles (void);
+
+/*-----------------------------------------------------------------
+FAT_FreeFiles
+Closes all open files then resets the CF card.
+Call this before exiting back to the GBAMP
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_FreeFiles (void);
+
+/*-----------------------------------------------------------------
+FAT_GetAlias
+Get the alias (short name) of the last file or directory entry read
+	using GetDirEntry. Works for FindFirstFile and FindNextFile
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetAlias (char* alias);
+
+/*-----------------------------------------------------------------
+FAT_GetLongFilename
+Get the long name of the last file or directory retrived with 
+	GetDirEntry. Also works for FindFirstFile and FindNextFile
+char* filename: OUT will be filled with the filename, should be at
+	least 256 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetLongFilename (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSize
+Get the file size of the last file found or openned.
+This idea is based on a modification by MoonShine
+u32 return OUT: the file size
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSize (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileCluster
+Get the first cluster of the last file found or openned.
+u32 return OUT: the file start cluster
+-----------------------------------------------------------------*/
+u32 FAT_GetFileCluster (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileAttributes
+Get the attributes of the last file found or openned.
+u8 return OUT: the file's attributes
+-----------------------------------------------------------------*/
+u8 FAT_GetFileAttributes (void);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_FAT_SetFileAttributes
+Set the attributes of a file.
+const char* filename IN: The name and path of the file to modify
+u8 attributes IN: The attribute values to assign
+u8 mask IN: Detemines which attributes are changed
+u8 return OUT: the file's new attributes
+-----------------------------------------------------------------*/
+u8 FAT_SetFileAttributes (const char* filename, u8 attributes, u8 mask);
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+/*-----------------------------------------------------------------
+FAT_GetFileCreationTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileCreationTime (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileLastWriteTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileLastWriteTime (void);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_FindNextFile
+Gets the name of the next directory entry
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFile (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFile
+Gets the name of the first directory entry and resets the count
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFile (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFileLFN
+Gets the long file name of the first directory entry and resets
+	the count (can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFileLFN(char* lfn);
+
+/*-----------------------------------------------------------------
+FAT_FindNextFileLFN
+Gets the long file name of the next directory entry
+	(can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFileLFN(char* lfn);
+
+/*-----------------------------------------------------------------
+FAT_FileExists
+Returns the type of file 
+char* filename: IN filename of the file to look for
+FILE_TYPE return: OUT returns FT_NONE if there is now file with 
+	that name, FT_FILE if it is a file and FT_DIR if it is a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FileExists (const char* filename);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemType
+FS_TYPE return: OUT returns the current file system type
+-----------------------------------------------------------------*/
+FS_TYPE FAT_GetFileSystemType (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemTotalSize
+u32 return: OUT returns the total disk space (used + free)
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSystemTotalSize (void);
+
+/*-----------------------------------------------------------------
+FAT_chdir
+Changes the current working directory
+const char* path: IN null terminated string of directory separated by 
+	forward slashes, / is root
+bool return: OUT returns true if successful
+-----------------------------------------------------------------*/
+bool FAT_chdir (const char* path);
+
+
+//-----------------------------------------------------------------
+// File functions
+
+/*-----------------------------------------------------------------
+FAT_fopen(filename, mode)
+Opens a file
+const char* path: IN null terminated string of filename and path 
+	separated by forward slashes, / is root
+const char* mode: IN mode to open file in
+	Supported modes: "r", "r+", "w", "w+", "a", "a+", don't use
+	"b" or "t" in any mode, as all files are openned in binary mode
+FAT_FILE* return: OUT handle to open file, returns -1 if the file 
+	couldn't be openned
+-----------------------------------------------------------------*/
+FAT_FILE* FAT_fopen(const char* path, const char* mode);
+
+/*-----------------------------------------------------------------
+FAT_fclose(file)
+Closes a file
+FAT_FILE* file: IN handle of the file to close
+bool return OUT: true if successful, false if not
+-----------------------------------------------------------------*/
+bool FAT_fclose (FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+FAT_ftell(file)
+Returns the current position in a file
+FAT_FILE* file: IN handle of an open file
+u32 OUT: Current position
+-----------------------------------------------------------------*/
+u32 FAT_ftell (FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+FAT_fseek(file, offset, origin)
+Seeks to specified byte position in file
+int file: IN handle of an open file
+u32 offset IN: position to seek to, relative to origin
+int origin IN: origin to seek from
+int OUT: Returns 0 if successful, -1 if not
+-----------------------------------------------------------------*/
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin);
+
+/*-----------------------------------------------------------------
+FAT_fread(buffer, size, count, file)
+Reads in length number of bytes into buffer from file, starting
+	from current position. It then sets the current position to the
+	byte after the last byte read. If it reaches the end of file
+	before filling the buffer then it stops reading.
+void* buffer OUT: Pointer to buffer to fill. Should be at least as
+	big as the number of bytes required
+u32 size IN: size of each item to read
+u32 count IN: number of items to read
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes read
+-----------------------------------------------------------------*/
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fwrite(buffer, size, count, file)
+Writes size * count bytes into file from buffer, starting
+	from current position. It then sets the current position to the
+	byte after the last byte written. If the file was openned in 
+	append mode it always writes to the end of the file.
+const void* buffer IN: Pointer to buffer containing data. Should be
+	at least as big as the number of bytes to be written.
+u32 size IN: size of each item to write
+u32 count IN: number of items to write
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes written
+-----------------------------------------------------------------*/
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_feof(file)
+Returns true if the end of file has been reached
+FAT_FILE* file IN: Handle of an open file
+bool return OUT: true if EOF, false if not
+-----------------------------------------------------------------*/
+bool FAT_feof(FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_remove (path)
+Deletes the file or empty directory sepecified in path
+const char* path IN: Path of item to delete
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_remove (const char* path);
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_mkdir (path)
+Makes a new directory, so long as no other directory or file has 
+	the same name.
+const char* path IN: Path and filename of directory to make
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_mkdir (const char* path);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgetc (handle)
+Gets the next character in the file
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fgetc (FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputc (character, handle)
+Writes the given character into the file
+char c IN: Character to be written
+FAT_FILE* handle IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fputc (char c, FAT_FILE* file);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgets (char *tgtBuffer, int num, FAT_FILE* file)
+Gets a up to num bytes from file, stopping at the first
+ newline.
+
+CAUTION: does not do strictly streaming. I.e. it's 
+ reading more then needed bytes and seeking back.
+ shouldn't matter for random access 
+
+char *tgtBuffer OUT: buffer to write to
+int num IN: size of target buffer
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Added check for unix style text files
+	* Removed seek when no newline is found, since it isn't necessary
+-------------------------------------------------------------------*/
+char *FAT_fgets(char *tgtBuffer, int num, FAT_FILE* file) ;
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputs (const char *string, FAT_FILE* file)
+Writes string to file, excluding end of string character
+const char *string IN: string to write
+FAT_FILE* file IN: Handle of open file
+bool return OUT: number of characters written if successful,
+	EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Uses FAT_FILE instead of int
+	* writtenBytes is now u32 instead of int
+-------------------------------------------------------------------*/
+int FAT_fputs (const char *string, FAT_FILE* file);
+#endif
+
+//------------------------------------------------------------------
+#ifdef __cplusplus
+}	   // extern "C"
+#endif
+//------------------------------------------------------------------
+
+#endif	// ifndef _GBA_NDS_FAT
+
+/*
+	gba_nds_fat.h
+	By chishm (Michael Chisholm)
+
+	Routines for reading a compact flash card
+	using the GBA Movie Player or M3.
+
+	Some FAT routines are based on those in fat.c, which
+	is part of avrlib by Pascal Stang.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+//---------------------------------------------------------------
+
+#ifndef _GBA_NDS_FAT_INCLUDED
+#define _GBA_NDS_FAT_INCLUDED
+
+//---------------------------------------------------------------
+// Customisable features
+
+// Maximum number of files open at once
+// Increase this to open more files, decrease to save memory
+#define MAX_FILES_OPEN	4
+
+// Allow file writing
+// Disable this to remove file writing support
+#define CAN_WRITE_TO_DISC
+
+// Allow file time functions
+// This adds ~ 14KB to the compiled size
+// Uncomment to enable
+// #define FILE_TIME_SUPPORT
+
+//---------------------------------------------------------------
+// Platform specific includes
+
+// When compiling for NDS, make sure NDS is defined
+#ifndef NDS
+ #if defined ARM9 || defined ARM7
+  #define NDS
+ #endif
+#endif
+
+#ifdef NDS
+ #include <nds/jtypes.h>
+#else
+ #include "gba_types.h"
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+ #include <time.h>
+#endif
+
+//---------------------------------------------------------------
+#ifdef __cplusplus
+extern "C" {
+#endif
+//---------------------------------------------------------------
+
+//---------------------------------------------------------------
+// Important constants
+
+
+#define MAX_FILENAME_LENGTH 256	// Maximum LFN length. Don't change this one
+
+// File Constants
+#ifndef EOF
+#define EOF -1
+#define SEEK_SET	0
+#define SEEK_CUR	1
+#define SEEK_END	2
+#endif
+
+// File attributes
+#define ATTRIB_ARCH	0x20			// Archive
+#define ATTRIB_DIR	0x10			// Directory
+#define ATTRIB_LFN	0x0F			// Long file name
+#define ATTRIB_VOL	0x08			// Volume
+#define ATTRIB_SYS	0x04			// System
+#define ATTRIB_HID	0x02			// Hidden
+#define ATTRIB_RO	0x01			// Read only
+
+
+// Directory Constants
+typedef enum {FT_NONE, FT_FILE, FT_DIR} FILE_TYPE;
+
+// Filesystem type
+typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
+
+// Open file information structure
+typedef struct
+{
+	u32 firstCluster;
+	u32 length;
+	u32 curPos;
+	u32 curClus;			// Current cluster to read from
+	int curSect;			// Current sector within cluster
+	int curByte;			// Current byte within sector
+	char readBuffer[512];	// Buffer used for unaligned reads
+	u32 appClus;			// Cluster to append to
+	int appSect;			// Sector within cluster for appending
+	int appByte;			// Byte within sector for appending
+	bool read;	// Can read from file
+	bool write;	// Can write to file
+	bool append;// Can append to file
+	bool inUse;	// This file is open
+	u32 dirEntSector;	// The sector where the directory entry is stored
+	int dirEntOffset;	// The offset within the directory sector
+}	FAT_FILE;
+
+
+//-----------------------------------------------------------------
+// CF Card functions
+
+/*-----------------------------------------------------------------
+FAT_InitFiles
+Reads the FAT information from the CF card.
+You need to call this before reading any files.
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_InitFiles (void);
+
+/*-----------------------------------------------------------------
+FAT_FreeFiles
+Closes all open files then resets the CF card.
+Call this before exiting back to the GBAMP
+bool return OUT: true if successful.
+-----------------------------------------------------------------*/
+bool FAT_FreeFiles (void);
+
+/*-----------------------------------------------------------------
+FAT_GetAlias
+Get the alias (short name) of the last file or directory entry read
+	using GetDirEntry. Works for FindFirstFile and FindNextFile
+char* alias OUT: will be filled with the alias (short filename),
+	should be at least 13 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetAlias (char* alias);
+
+/*-----------------------------------------------------------------
+FAT_GetLongFilename
+Get the long name of the last file or directory retrived with 
+	GetDirEntry. Also works for FindFirstFile and FindNextFile
+char* filename: OUT will be filled with the filename, should be at
+	least 256 bytes long
+bool return OUT: return true if successful
+-----------------------------------------------------------------*/
+bool FAT_GetLongFilename (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSize
+Get the file size of the last file found or openned.
+This idea is based on a modification by MoonShine
+u32 return OUT: the file size
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSize (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileCluster
+Get the first cluster of the last file found or openned.
+u32 return OUT: the file start cluster
+-----------------------------------------------------------------*/
+u32 FAT_GetFileCluster (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileAttributes
+Get the attributes of the last file found or openned.
+u8 return OUT: the file's attributes
+-----------------------------------------------------------------*/
+u8 FAT_GetFileAttributes (void);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_FAT_SetFileAttributes
+Set the attributes of a file.
+const char* filename IN: The name and path of the file to modify
+u8 attributes IN: The attribute values to assign
+u8 mask IN: Detemines which attributes are changed
+u8 return OUT: the file's new attributes
+-----------------------------------------------------------------*/
+u8 FAT_SetFileAttributes (const char* filename, u8 attributes, u8 mask);
+#endif
+
+#ifdef FILE_TIME_SUPPORT
+/*-----------------------------------------------------------------
+FAT_GetFileCreationTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileCreationTime (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileLastWriteTime
+Get the creation time of the last file found or openned.
+time_t return OUT: the file's creation time
+-----------------------------------------------------------------*/
+time_t FAT_GetFileLastWriteTime (void);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_FindNextFile
+Gets the name of the next directory entry
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFile (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFile
+Gets the name of the first directory entry and resets the count
+	(can be a file or subdirectory)
+char* filename: OUT filename, must be at least 13 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFile (char* filename);
+
+/*-----------------------------------------------------------------
+FAT_FindFirstFileLFN
+Gets the long file name of the first directory entry and resets
+	the count (can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindFirstFileLFN(char* lfn);
+
+/*-----------------------------------------------------------------
+FAT_FindNextFileLFN
+Gets the long file name of the next directory entry
+	(can be a file or subdirectory)
+char* lfn: OUT long file name, must be at least 256 chars long
+FILE_TYPE return: OUT returns FT_NONE if failed, 
+	FT_FILE if it found a file and FT_DIR if it found a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FindNextFileLFN(char* lfn);
+
+/*-----------------------------------------------------------------
+FAT_FileExists
+Returns the type of file 
+char* filename: IN filename of the file to look for
+FILE_TYPE return: OUT returns FT_NONE if there is now file with 
+	that name, FT_FILE if it is a file and FT_DIR if it is a directory
+-----------------------------------------------------------------*/
+FILE_TYPE FAT_FileExists (const char* filename);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemType
+FS_TYPE return: OUT returns the current file system type
+-----------------------------------------------------------------*/
+FS_TYPE FAT_GetFileSystemType (void);
+
+/*-----------------------------------------------------------------
+FAT_GetFileSystemTotalSize
+u32 return: OUT returns the total disk space (used + free)
+-----------------------------------------------------------------*/
+u32 FAT_GetFileSystemTotalSize (void);
+
+/*-----------------------------------------------------------------
+FAT_chdir
+Changes the current working directory
+const char* path: IN null terminated string of directory separated by 
+	forward slashes, / is root
+bool return: OUT returns true if successful
+-----------------------------------------------------------------*/
+bool FAT_chdir (const char* path);
+
+
+//-----------------------------------------------------------------
+// File functions
+
+/*-----------------------------------------------------------------
+FAT_fopen(filename, mode)
+Opens a file
+const char* path: IN null terminated string of filename and path 
+	separated by forward slashes, / is root
+const char* mode: IN mode to open file in
+	Supported modes: "r", "r+", "w", "w+", "a", "a+", don't use
+	"b" or "t" in any mode, as all files are openned in binary mode
+FAT_FILE* return: OUT handle to open file, returns -1 if the file 
+	couldn't be openned
+-----------------------------------------------------------------*/
+FAT_FILE* FAT_fopen(const char* path, const char* mode);
+
+/*-----------------------------------------------------------------
+FAT_fclose(file)
+Closes a file
+FAT_FILE* file: IN handle of the file to close
+bool return OUT: true if successful, false if not
+-----------------------------------------------------------------*/
+bool FAT_fclose (FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+FAT_ftell(file)
+Returns the current position in a file
+FAT_FILE* file: IN handle of an open file
+u32 OUT: Current position
+-----------------------------------------------------------------*/
+u32 FAT_ftell (FAT_FILE* file);
+
+/*-----------------------------------------------------------------
+FAT_fseek(file, offset, origin)
+Seeks to specified byte position in file
+int file: IN handle of an open file
+u32 offset IN: position to seek to, relative to origin
+int origin IN: origin to seek from
+int OUT: Returns 0 if successful, -1 if not
+-----------------------------------------------------------------*/
+int FAT_fseek(FAT_FILE* file, s32 offset, int origin);
+
+/*-----------------------------------------------------------------
+FAT_fread(buffer, size, count, file)
+Reads in length number of bytes into buffer from file, starting
+	from current position. It then sets the current position to the
+	byte after the last byte read. If it reaches the end of file
+	before filling the buffer then it stops reading.
+void* buffer OUT: Pointer to buffer to fill. Should be at least as
+	big as the number of bytes required
+u32 size IN: size of each item to read
+u32 count IN: number of items to read
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes read
+-----------------------------------------------------------------*/
+u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fwrite(buffer, size, count, file)
+Writes size * count bytes into file from buffer, starting
+	from current position. It then sets the current position to the
+	byte after the last byte written. If the file was openned in 
+	append mode it always writes to the end of the file.
+const void* buffer IN: Pointer to buffer containing data. Should be
+	at least as big as the number of bytes to be written.
+u32 size IN: size of each item to write
+u32 count IN: number of items to write
+FAT_FILE* file IN: Handle of an open file
+u32 OUT: returns the actual number of bytes written
+-----------------------------------------------------------------*/
+u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_feof(file)
+Returns true if the end of file has been reached
+FAT_FILE* file IN: Handle of an open file
+bool return OUT: true if EOF, false if not
+-----------------------------------------------------------------*/
+bool FAT_feof(FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_remove (path)
+Deletes the file or empty directory sepecified in path
+const char* path IN: Path of item to delete
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_remove (const char* path);
+#endif
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_mkdir (path)
+Makes a new directory, so long as no other directory or file has 
+	the same name.
+const char* path IN: Path and filename of directory to make
+int return OUT: zero if successful, non-zero if not
+-----------------------------------------------------------------*/
+int FAT_mkdir (const char* path);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgetc (handle)
+Gets the next character in the file
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fgetc (FAT_FILE* file);
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputc (character, handle)
+Writes the given character into the file
+char c IN: Character to be written
+FAT_FILE* handle IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+-----------------------------------------------------------------*/
+char FAT_fputc (char c, FAT_FILE* file);
+#endif
+
+/*-----------------------------------------------------------------
+FAT_fgets (char *tgtBuffer, int num, FAT_FILE* file)
+Gets a up to num bytes from file, stopping at the first
+ newline.
+
+CAUTION: does not do strictly streaming. I.e. it's 
+ reading more then needed bytes and seeking back.
+ shouldn't matter for random access 
+
+char *tgtBuffer OUT: buffer to write to
+int num IN: size of target buffer
+FAT_FILE* file IN: Handle of open file
+bool return OUT: character if successful, EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Added check for unix style text files
+	* Removed seek when no newline is found, since it isn't necessary
+-------------------------------------------------------------------*/
+char *FAT_fgets(char *tgtBuffer, int num, FAT_FILE* file) ;
+
+#ifdef CAN_WRITE_TO_DISC
+/*-----------------------------------------------------------------
+FAT_fputs (const char *string, FAT_FILE* file)
+Writes string to file, excluding end of string character
+const char *string IN: string to write
+FAT_FILE* file IN: Handle of open file
+bool return OUT: number of characters written if successful,
+	EOF if not
+
+  Written by MightyMax
+  Modified by Chishm - 2005-11-17
+	* Uses FAT_FILE instead of int
+	* writtenBytes is now u32 instead of int
+-------------------------------------------------------------------*/
+int FAT_fputs (const char *string, FAT_FILE* file);
+#endif
+
+//------------------------------------------------------------------
+#ifdef __cplusplus
+}	   // extern "C"
+#endif
+//------------------------------------------------------------------
+
+#endif	// ifndef _GBA_NDS_FAT
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/gba_nds_fat.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,642 @@
+/*
+io_efa2.c by CyteX
+
+Based on io_mpfc.c by chishm (Michael Chisholm)
+
+Hardware Routines for reading the NAND flash located on
+EFA2 flash carts
+
+This software is completely free. No warranty is provided.
+If you use it, please give me credit and email me about your
+project at cytex <at> gmx <dot> de and do not forget to also
+drop chishm <at> hotmail <dot> com a line
+
+See gba_nds_fat.txt for help and license details.
+*/
+
+#include "io_efa2.h"
+
+#ifdef SUPPORT_EFA2
+
+//
+// EFA2 register addresses
+//
+
+// RTC registers
+#define REG_RTC_CLK        *(vu16*)0x080000c4
+#define REG_RTC_EN         *(vu16*)0x080000c8
+
+// "Magic" registers used for unlock/lock sequences
+#define REG_EFA2_MAGIC_A   *(vu16*)0x09fe0000
+#define REG_EFA2_MAGIC_B   *(vu16*)0x08000000
+#define REG_EFA2_MAGIC_C   *(vu16*)0x08020000
+#define REG_EFA2_MAGIC_D   *(vu16*)0x08040000
+#define REG_EFA2_MAGIC_E   *(vu16*)0x09fc0000
+
+// NAND flash lock/unlock register
+#define REG_EFA2_NAND_LOCK *(vu16*)0x09c40000
+// NAND flash enable register
+#define REG_EFA2_NAND_EN   *(vu16*)0x09400000
+// NAND flash command write register
+#define REG_EFA2_NAND_CMD   *(vu8*)0x09ffffe2
+// NAND flash address/data write register
+#define REG_EFA2_NAND_WR    *(vu8*)0x09ffffe0
+// NAND flash data read register
+#define REG_EFA2_NAND_RD    *(vu8*)0x09ffc000
+
+// ID of Samsung K9K1G NAND flash chip
+#define EFA2_NAND_ID 0xEC79A5C0
+
+// first sector of udisk 
+#define EFA2_UDSK_START 0x40
+
+//
+// EFA2 access functions
+//
+
+// deactivate RTC ports
+inline void efa2_rtc_deactivate(void) {
+	REG_RTC_EN = 0;
+}
+
+// unlock register access
+void efa2_reg_unlock(void) {
+	REG_EFA2_MAGIC_A = 0x0d200;
+	REG_EFA2_MAGIC_B = 0x01500;
+	REG_EFA2_MAGIC_C = 0x0d200;
+	REG_EFA2_MAGIC_D = 0x01500;
+}
+
+// finish/lock register access
+inline void efa2_reg_lock(void) {
+	REG_EFA2_MAGIC_E = 0x1500;
+}
+
+// global reset/init/enable/unlock ?
+void efa2_global_unlock(void) {
+	efa2_reg_unlock();
+	*(vu16*)0x09880000 = 0x08000;
+	efa2_reg_lock();
+}
+
+// global lock, stealth mode
+void efa2_global_lock(void) {
+	// quite sure there is such a sequence, but haven't had
+	// a look for it upto now
+}
+
+// unlock NAND Flash
+void efa2_nand_unlock(void) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_LOCK = 0x01500;
+	efa2_reg_lock();
+}
+
+// lock NAND Flash
+void efa2_nand_lock(void) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_LOCK = 0x0d200;
+	efa2_reg_lock();
+}
+
+//
+// Set NAND Flash chip enable and write protection bits ?
+// 
+//   val | ~CE | ~WP |
+//  -----+-----+-----+
+//     0 |  0  |  0  |
+//     1 |  1  |  0  |
+//     3 |  1  |  1  |
+//  -----+-----+-----+
+//
+void efa2_nand_enable(u16 val) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_EN = val;
+	efa2_reg_lock();
+}
+
+//
+// Perform NAND reset
+// NAND has to be unlocked and enabled when called
+//
+inline void efa2_nand_reset(void) {
+	REG_EFA2_NAND_CMD = 0xff; // write reset command
+}
+
+//
+// Read out NAND ID information, could be used for card detection
+// 
+//                    | EFA2 1GBit |
+//  ------------------+------------+
+//         maker code |    0xEC    |
+//        device code |    0x79    |
+//         don't care |    0xA5    |
+//   multi plane code |    0xC0    |
+//  ------------------+------------+
+//
+u32 efa2_nand_id(void) {
+	u8 byte;
+	u32 id;
+
+	efa2_nand_unlock();
+	efa2_nand_enable(1);
+
+	REG_EFA2_NAND_CMD = 0x90;  // write id command
+	REG_EFA2_NAND_WR  = 0x00;  // (dummy) address cycle
+	byte = REG_EFA2_NAND_RD;   // read maker code
+	id   = byte;
+	byte = REG_EFA2_NAND_RD;   // read device code
+	id   = (id << 8) | byte;
+	byte = REG_EFA2_NAND_RD;   // read don't care
+	id   = (id << 8) | byte;
+	byte = REG_EFA2_NAND_RD;   // read multi plane code
+	id   = (id << 8) | byte;
+
+	efa2_nand_enable(0);
+	efa2_nand_lock();
+	return (id);
+}
+
+//
+// Start of gba_nds_fat block device description
+//
+
+/*-----------------------------------------------------------------
+EFA2_ClearStatus
+Reads and checks NAND status information
+bool return OUT:  true if NAND is idle
+-----------------------------------------------------------------*/
+bool EFA2_ClearStatus (void) 
+{
+	// tbd: currently there is no write support, so always return
+	// true, there is no possibility for pending operations
+	return true;
+}
+
+/*-----------------------------------------------------------------
+EFA2_IsInserted
+Checks to see if the NAND chip used by the EFA2 is present
+bool return OUT:  true if the correct NAND chip is found
+-----------------------------------------------------------------*/
+bool EFA2_IsInserted (void) 
+{
+	EFA2_ClearStatus();
+	return (efa2_nand_id() == EFA2_NAND_ID);
+}
+
+/*-----------------------------------------------------------------
+EFA2_ReadSectors
+Read "numSecs" 512 byte sectors starting from "sector" into "buffer"
+No error correction, no use of spare cells, no use of R/~B signal
+u32 sector IN: number of first 512 byte sector to be read
+u8 numSecs IN: number of 512 byte sectors to read,
+1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool EFA2_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int  i;
+	int  j = (numSecs > 0 ? numSecs : 256);
+
+#ifndef _CF_ALLOW_UNALIGNED
+	u8  byte;
+	u16  word;
+#endif
+
+	// NAND page 0x40 (EFA2_UDSK_START) contains the MBR of the
+	// udisk and thus is sector 0. The original EFA2 firmware
+	// does never look at this, it only watches page 0x60, which
+	// contains the boot block of the FAT16 partition. That is
+	// fixed, so the EFA2 udisk must not be reformated, else
+	// the ARK Octopus and also the original Firmware won't be
+	// able to access the udisk anymore and I have to write a
+	// recovery tool.
+	u32 page = EFA2_UDSK_START + sector;
+
+	// future enhancement: wait for possible write operations to
+	// be finisched
+	if (!EFA2_ClearStatus()) return false;
+
+	efa2_nand_unlock();
+	efa2_nand_enable(1);
+	efa2_nand_reset();
+
+	// set NAND to READ1 operation mode and transfer page address
+	REG_EFA2_NAND_CMD = 0x00;                // write READ1 command  
+	REG_EFA2_NAND_WR  = 0x00;                // write address  [7:0]
+	REG_EFA2_NAND_WR  = (page      ) & 0xff; // write address [15:8]
+	REG_EFA2_NAND_WR  = (page >> 8 ) & 0xff; // write address[23:16]
+	REG_EFA2_NAND_WR  = (page >> 16) & 0xff; // write address[26:24]
+
+	// Due to a bug in EFA2 design there is need to waste some cycles
+	// "by hand" instead the possibility to check the R/~B port of
+	// the NAND flash via a register. The RTC deactivation is only
+	// there to make sure the loop won't be optimized by the compiler
+	for (i=0 ; i < 3 ; i++) efa2_rtc_deactivate();
+
+	while (j--)
+	{
+		// read page data
+#ifdef _CF_ALLOW_UNALIGNED
+		// slow byte access to RAM, but works in principle
+		for (i=0 ; i < 512 ; i++)
+			((u8*)buffer)[i] = REG_EFA2_NAND_RD;
+#else
+		// a bit faster, but DMA is not possible
+		for (i=0 ; i < 256 ; i++) {
+			byte = REG_EFA2_NAND_RD;   // read lo-byte
+			word = byte;
+			byte = REG_EFA2_NAND_RD;   // read hi-byte
+			word = word | (byte << 8);
+			((u16*)buffer)[i] = word;
+		}
+#endif
+	}
+
+	efa2_nand_enable(0);
+	efa2_nand_lock();
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+EFA2_WriteSectors
+Write "numSecs" 512 byte sectors starting at "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on card to write
+u8 numSecs IN: number of 512 byte sectors to write
+1 to 256 sectors can be written, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool EFA2_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	// Upto now I focused on reading NAND, write operations
+	// will follow
+	return false;
+}
+
+/*-----------------------------------------------------------------
+EFA2_Shutdown
+unload the EFA2 interface
+-----------------------------------------------------------------*/
+bool EFA2_Shutdown(void) 
+{
+	return EFA2_ClearStatus();
+}
+
+/*-----------------------------------------------------------------
+EFA2_StartUp
+initializes the EFA2 card, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool EFA2_StartUp(void)
+{
+	efa2_global_unlock();
+	return (efa2_nand_id() == EFA2_NAND_ID);
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_efa2 = {
+	DEVICE_TYPE_EFA2,
+	FEATURE_MEDIUM_CANREAD | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&EFA2_StartUp,
+	(FN_MEDIUM_ISINSERTED)&EFA2_IsInserted,
+	(FN_MEDIUM_READSECTORS)&EFA2_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&EFA2_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&EFA2_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&EFA2_Shutdown
+};
+
+/*-----------------------------------------------------------------
+EFA2_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE EFA2_GetInterface(void) {
+	return &io_efa2;
+}
+
+#endif // SUPPORT_EFA2
+/*
+io_efa2.c by CyteX
+
+Based on io_mpfc.c by chishm (Michael Chisholm)
+
+Hardware Routines for reading the NAND flash located on
+EFA2 flash carts
+
+This software is completely free. No warranty is provided.
+If you use it, please give me credit and email me about your
+project at cytex <at> gmx <dot> de and do not forget to also
+drop chishm <at> hotmail <dot> com a line
+
+See gba_nds_fat.txt for help and license details.
+*/
+
+#include "io_efa2.h"
+
+#ifdef SUPPORT_EFA2
+
+//
+// EFA2 register addresses
+//
+
+// RTC registers
+#define REG_RTC_CLK        *(vu16*)0x080000c4
+#define REG_RTC_EN         *(vu16*)0x080000c8
+
+// "Magic" registers used for unlock/lock sequences
+#define REG_EFA2_MAGIC_A   *(vu16*)0x09fe0000
+#define REG_EFA2_MAGIC_B   *(vu16*)0x08000000
+#define REG_EFA2_MAGIC_C   *(vu16*)0x08020000
+#define REG_EFA2_MAGIC_D   *(vu16*)0x08040000
+#define REG_EFA2_MAGIC_E   *(vu16*)0x09fc0000
+
+// NAND flash lock/unlock register
+#define REG_EFA2_NAND_LOCK *(vu16*)0x09c40000
+// NAND flash enable register
+#define REG_EFA2_NAND_EN   *(vu16*)0x09400000
+// NAND flash command write register
+#define REG_EFA2_NAND_CMD   *(vu8*)0x09ffffe2
+// NAND flash address/data write register
+#define REG_EFA2_NAND_WR    *(vu8*)0x09ffffe0
+// NAND flash data read register
+#define REG_EFA2_NAND_RD    *(vu8*)0x09ffc000
+
+// ID of Samsung K9K1G NAND flash chip
+#define EFA2_NAND_ID 0xEC79A5C0
+
+// first sector of udisk 
+#define EFA2_UDSK_START 0x40
+
+//
+// EFA2 access functions
+//
+
+// deactivate RTC ports
+inline void efa2_rtc_deactivate(void) {
+	REG_RTC_EN = 0;
+}
+
+// unlock register access
+void efa2_reg_unlock(void) {
+	REG_EFA2_MAGIC_A = 0x0d200;
+	REG_EFA2_MAGIC_B = 0x01500;
+	REG_EFA2_MAGIC_C = 0x0d200;
+	REG_EFA2_MAGIC_D = 0x01500;
+}
+
+// finish/lock register access
+inline void efa2_reg_lock(void) {
+	REG_EFA2_MAGIC_E = 0x1500;
+}
+
+// global reset/init/enable/unlock ?
+void efa2_global_unlock(void) {
+	efa2_reg_unlock();
+	*(vu16*)0x09880000 = 0x08000;
+	efa2_reg_lock();
+}
+
+// global lock, stealth mode
+void efa2_global_lock(void) {
+	// quite sure there is such a sequence, but haven't had
+	// a look for it upto now
+}
+
+// unlock NAND Flash
+void efa2_nand_unlock(void) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_LOCK = 0x01500;
+	efa2_reg_lock();
+}
+
+// lock NAND Flash
+void efa2_nand_lock(void) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_LOCK = 0x0d200;
+	efa2_reg_lock();
+}
+
+//
+// Set NAND Flash chip enable and write protection bits ?
+// 
+//   val | ~CE | ~WP |
+//  -----+-----+-----+
+//     0 |  0  |  0  |
+//     1 |  1  |  0  |
+//     3 |  1  |  1  |
+//  -----+-----+-----+
+//
+void efa2_nand_enable(u16 val) {
+	efa2_reg_unlock();
+	REG_EFA2_NAND_EN = val;
+	efa2_reg_lock();
+}
+
+//
+// Perform NAND reset
+// NAND has to be unlocked and enabled when called
+//
+inline void efa2_nand_reset(void) {
+	REG_EFA2_NAND_CMD = 0xff; // write reset command
+}
+
+//
+// Read out NAND ID information, could be used for card detection
+// 
+//                    | EFA2 1GBit |
+//  ------------------+------------+
+//         maker code |    0xEC    |
+//        device code |    0x79    |
+//         don't care |    0xA5    |
+//   multi plane code |    0xC0    |
+//  ------------------+------------+
+//
+u32 efa2_nand_id(void) {
+	u8 byte;
+	u32 id;
+
+	efa2_nand_unlock();
+	efa2_nand_enable(1);
+
+	REG_EFA2_NAND_CMD = 0x90;  // write id command
+	REG_EFA2_NAND_WR  = 0x00;  // (dummy) address cycle
+	byte = REG_EFA2_NAND_RD;   // read maker code
+	id   = byte;
+	byte = REG_EFA2_NAND_RD;   // read device code
+	id   = (id << 8) | byte;
+	byte = REG_EFA2_NAND_RD;   // read don't care
+	id   = (id << 8) | byte;
+	byte = REG_EFA2_NAND_RD;   // read multi plane code
+	id   = (id << 8) | byte;
+
+	efa2_nand_enable(0);
+	efa2_nand_lock();
+	return (id);
+}
+
+//
+// Start of gba_nds_fat block device description
+//
+
+/*-----------------------------------------------------------------
+EFA2_ClearStatus
+Reads and checks NAND status information
+bool return OUT:  true if NAND is idle
+-----------------------------------------------------------------*/
+bool EFA2_ClearStatus (void) 
+{
+	// tbd: currently there is no write support, so always return
+	// true, there is no possibility for pending operations
+	return true;
+}
+
+/*-----------------------------------------------------------------
+EFA2_IsInserted
+Checks to see if the NAND chip used by the EFA2 is present
+bool return OUT:  true if the correct NAND chip is found
+-----------------------------------------------------------------*/
+bool EFA2_IsInserted (void) 
+{
+	EFA2_ClearStatus();
+	return (efa2_nand_id() == EFA2_NAND_ID);
+}
+
+/*-----------------------------------------------------------------
+EFA2_ReadSectors
+Read "numSecs" 512 byte sectors starting from "sector" into "buffer"
+No error correction, no use of spare cells, no use of R/~B signal
+u32 sector IN: number of first 512 byte sector to be read
+u8 numSecs IN: number of 512 byte sectors to read,
+1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool EFA2_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int  i;
+	int  j = (numSecs > 0 ? numSecs : 256);
+
+#ifndef _CF_ALLOW_UNALIGNED
+	u8  byte;
+	u16  word;
+#endif
+
+	// NAND page 0x40 (EFA2_UDSK_START) contains the MBR of the
+	// udisk and thus is sector 0. The original EFA2 firmware
+	// does never look at this, it only watches page 0x60, which
+	// contains the boot block of the FAT16 partition. That is
+	// fixed, so the EFA2 udisk must not be reformated, else
+	// the ARK Octopus and also the original Firmware won't be
+	// able to access the udisk anymore and I have to write a
+	// recovery tool.
+	u32 page = EFA2_UDSK_START + sector;
+
+	// future enhancement: wait for possible write operations to
+	// be finisched
+	if (!EFA2_ClearStatus()) return false;
+
+	efa2_nand_unlock();
+	efa2_nand_enable(1);
+	efa2_nand_reset();
+
+	// set NAND to READ1 operation mode and transfer page address
+	REG_EFA2_NAND_CMD = 0x00;                // write READ1 command  
+	REG_EFA2_NAND_WR  = 0x00;                // write address  [7:0]
+	REG_EFA2_NAND_WR  = (page      ) & 0xff; // write address [15:8]
+	REG_EFA2_NAND_WR  = (page >> 8 ) & 0xff; // write address[23:16]
+	REG_EFA2_NAND_WR  = (page >> 16) & 0xff; // write address[26:24]
+
+	// Due to a bug in EFA2 design there is need to waste some cycles
+	// "by hand" instead the possibility to check the R/~B port of
+	// the NAND flash via a register. The RTC deactivation is only
+	// there to make sure the loop won't be optimized by the compiler
+	for (i=0 ; i < 3 ; i++) efa2_rtc_deactivate();
+
+	while (j--)
+	{
+		// read page data
+#ifdef _CF_ALLOW_UNALIGNED
+		// slow byte access to RAM, but works in principle
+		for (i=0 ; i < 512 ; i++)
+			((u8*)buffer)[i] = REG_EFA2_NAND_RD;
+#else
+		// a bit faster, but DMA is not possible
+		for (i=0 ; i < 256 ; i++) {
+			byte = REG_EFA2_NAND_RD;   // read lo-byte
+			word = byte;
+			byte = REG_EFA2_NAND_RD;   // read hi-byte
+			word = word | (byte << 8);
+			((u16*)buffer)[i] = word;
+		}
+#endif
+	}
+
+	efa2_nand_enable(0);
+	efa2_nand_lock();
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+EFA2_WriteSectors
+Write "numSecs" 512 byte sectors starting at "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on card to write
+u8 numSecs IN: number of 512 byte sectors to write
+1 to 256 sectors can be written, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool EFA2_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	// Upto now I focused on reading NAND, write operations
+	// will follow
+	return false;
+}
+
+/*-----------------------------------------------------------------
+EFA2_Shutdown
+unload the EFA2 interface
+-----------------------------------------------------------------*/
+bool EFA2_Shutdown(void) 
+{
+	return EFA2_ClearStatus();
+}
+
+/*-----------------------------------------------------------------
+EFA2_StartUp
+initializes the EFA2 card, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool EFA2_StartUp(void)
+{
+	efa2_global_unlock();
+	return (efa2_nand_id() == EFA2_NAND_ID);
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_efa2 = {
+	DEVICE_TYPE_EFA2,
+	FEATURE_MEDIUM_CANREAD | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&EFA2_StartUp,
+	(FN_MEDIUM_ISINSERTED)&EFA2_IsInserted,
+	(FN_MEDIUM_READSECTORS)&EFA2_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&EFA2_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&EFA2_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&EFA2_Shutdown
+};
+
+/*-----------------------------------------------------------------
+EFA2_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE EFA2_GetInterface(void) {
+	return &io_efa2;
+}
+
+#endif // SUPPORT_EFA2


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,56 @@
+/*
+  io_efa2.h by CyteX
+
+  Based on io_mpfc.h by chishm (Michael Chisholm)
+
+  Hardware Routines for reading the NAND flash located on
+  EFA2 flash carts
+
+  This software is completely free. No warranty is provided.
+  If you use it, please give me credit and email me about your
+  project at cytex <at> gmx <dot> de and do not forget to also
+  drop chishm <at> hotmail <dot> com a line
+
+  See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_EFA2_H
+#define IO_EFA2_H
+
+// 'EFA2'
+#define DEVICE_TYPE_EFA2 0x32414645
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE EFA2_GetInterface(void);
+
+#endif	// define IO_EFA2_H
+/*
+  io_efa2.h by CyteX
+
+  Based on io_mpfc.h by chishm (Michael Chisholm)
+
+  Hardware Routines for reading the NAND flash located on
+  EFA2 flash carts
+
+  This software is completely free. No warranty is provided.
+  If you use it, please give me credit and email me about your
+  project at cytex <at> gmx <dot> de and do not forget to also
+  drop chishm <at> hotmail <dot> com a line
+
+  See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_EFA2_H
+#define IO_EFA2_H
+
+// 'EFA2'
+#define DEVICE_TYPE_EFA2 0x32414645
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE EFA2_GetInterface(void);
+
+#endif	// define IO_EFA2_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_efa2.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,658 @@
+/*
+	io_fcsr.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for using a GBA Flash Cart and SRAM as a 
+	block device.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+
+	The file system must be 512 byte aligned, in cart address space.
+	SRAM is supported.
+*/
+
+
+#include "io_fcsr.h"
+
+#ifdef SUPPORT_FCSR
+#include <string.h>
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+#ifdef NDS
+ #define SRAM_START 0x0A000000
+#else
+ #define SRAM_START 0x0E000000
+#endif
+
+#define NO_SRAM 0xFFFFFFFF
+
+#define FCSR 0x52534346
+const char FCSR_LabelString[] = " Chishm FAT";
+
+u8* FCSR_FileSysPointer = 0;
+u8* FCSR_SramSectorPointer[4] = {0,0,0,0};
+u32 FCSR_SramSectorStart[4] = {0,0,0,0};
+u32 FCSR_SramSectorEnd[4] = {0,0,0,0};
+
+/*-----------------------------------------------------------------
+FCSR_IsInserted
+Is a GBA Flash Cart with a valid file system inserted?
+bool return OUT:  true if a GBA FC card is inserted
+-----------------------------------------------------------------*/
+bool FCSR_IsInserted (void) 
+{
+	bool flagFoundFileSys = false;
+
+	u32* fileSysPointer = (u32*)0x08000100;		// Start at beginning of cart address space, offset by expected location of string
+
+	// Search for file system
+	while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)	// Only search while not at end of cart address space
+	{
+		while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
+			fileSysPointer += 0x40;
+		if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
+		{
+			flagFoundFileSys = true;
+		} else {
+			fileSysPointer += 0x80;
+		}
+	}
+
+	return flagFoundFileSys;
+}
+
+
+/*-----------------------------------------------------------------
+FCSR_ClearStatus
+Finish any pending operations
+bool return OUT:  always true for GBA FC
+-----------------------------------------------------------------*/
+bool FCSR_ClearStatus (void) 
+{
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+FCSR_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on Flash Cart to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FCSR_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{	
+	int i;
+	bool flagSramSector = false;
+	int numSectors = (numSecs > 0 ? numSecs : 256);
+	int readLength = numSectors * BYTE_PER_READ;
+	u8* src;;
+	u8* dst;
+
+	// Find which region this read is in
+	for (i = 0; (i < 4) && !flagSramSector; i++)
+	{
+		if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
+		{
+			flagSramSector = true;
+			break;
+		}
+	}
+
+	// Make sure read will be completely in SRAM range if it is partially there
+	if ( flagSramSector && ((sector + numSectors) > FCSR_SramSectorEnd[i]))
+		return false;
+
+	// Copy data to buffer
+	if (flagSramSector)
+	{
+		src = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
+	} else {
+		src = FCSR_FileSysPointer + sector * BYTE_PER_READ;
+	}
+	dst = (u8*)buffer;
+
+	if (flagSramSector)
+	{
+		while (readLength--)
+		{
+			*dst++ = *src++;
+		}
+	} else {	// Reading from Cart ROM
+
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+  #ifdef ARM9
+		DC_FlushRange( buffer, readLength);
+  #endif	// ARM9
+		DMA3_SRC = (u32)src;
+		DMA3_DEST = (u32)buffer;
+		DMA3_CR = (readLength >> 1) | DMA_COPY_HALFWORDS;
+ #else	// ! NDS
+		DMA3COPY ( src, buffer, (readLength >> 1) | DMA16 | DMA_ENABLE);
+ #endif	// NDS
+#else	// !_CF_USE_DMA
+		memcpy (buffer, src, readLength);
+#endif	// _CF_USE_DMA
+
+	}	// if (flagSramSector)
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on Flash Cart to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FCSR_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	bool flagSramSector = false;
+	int writeLength = (numSecs > 0 ? numSecs : 256) * BYTE_PER_READ;
+	u8* src = (u8*) buffer;
+	u8* dst;
+
+	// Find which region this sector belongs in
+	for (i = 0; (i < 4) && !flagSramSector; i++)
+	{
+		if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
+		{
+			flagSramSector = true;
+			break;
+		}
+	}
+
+	if (!flagSramSector)
+		return false;
+
+	// Entire write must be within an SRAM region
+	if ((sector + (numSecs > 0 ? numSecs : 256)) > FCSR_SramSectorEnd[i])
+		return false;
+
+	// Copy data to SRAM
+	dst = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
+	while (writeLength--)
+	{
+		*dst++ = *src++;
+	}
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_Shutdown
+unload the Flash Cart interface
+-----------------------------------------------------------------*/
+bool FCSR_Shutdown(void) 
+{
+	int i;
+	if (FCSR_ClearStatus() == false)
+		return false;
+
+	FCSR_FileSysPointer = 0;
+	
+	for (i=0; i < 4; i++)
+	{
+		FCSR_SramSectorPointer[i] = 0;
+		FCSR_SramSectorStart[i] = 0;
+		FCSR_SramSectorEnd[i] = 0;
+	}
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_StartUp
+initializes the Flash Cart interface, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool FCSR_StartUp(void)
+{
+	bool flagFoundFileSys = false;
+	int i;
+	int SramRegionSize[4];
+	u8* srcByte;
+	u8* destByte;
+
+	u32* fileSysPointer = (u32*)0x08000100;		// Start at beginning of cart address space, offset by expected location of string
+
+	// Search for file system
+	while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)	// Only search while not at end of cart address space
+	{
+		while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
+			fileSysPointer += 0x40;
+		if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
+		{
+			flagFoundFileSys = true;
+		} else {
+			fileSysPointer += 0x80;
+		}
+	}
+
+	if (!flagFoundFileSys)
+		return false;
+
+	// Flash cart file system pointer has been found
+	FCSR_FileSysPointer = (u8*)(fileSysPointer - 0x40);
+
+	// Get SRAM sector regions from header block
+	for (i = 0; i < 4; i++)
+	{
+		FCSR_SramSectorStart[i] = fileSysPointer[i+4];	
+		SramRegionSize[i] = fileSysPointer[i+8];
+		FCSR_SramSectorEnd[i] = FCSR_SramSectorStart[i] + SramRegionSize[i];
+	}
+	
+	// Calculate SRAM region pointers
+	FCSR_SramSectorPointer[0] = (u8*)(SRAM_START + 4);
+	for (i = 1; i < 4; i++)
+	{
+		FCSR_SramSectorPointer[i] = FCSR_SramSectorPointer[i-1] + (SramRegionSize[i-1] * BYTE_PER_READ);
+	}
+
+	// Initialise SRAM with overlay if it hasn't been done so
+	if ( (*((u8*)SRAM_START) != 'F')  || (*((u8*)(SRAM_START+1)) != 'C') || (*((u8*)(SRAM_START+2)) != 'S') || (*((u8*)(SRAM_START+3)) != 'R') )
+	{
+		*((u8*)SRAM_START) = 'F';
+		*((u8*)(SRAM_START+1)) = 'C';
+		*((u8*)(SRAM_START+2)) = 'S';
+		*((u8*)(SRAM_START+3)) = 'R';
+
+		for (i = 0; i < 4; i++)
+		{
+			srcByte = FCSR_FileSysPointer + (FCSR_SramSectorStart[i] * BYTE_PER_READ);
+			destByte = FCSR_SramSectorPointer[i];
+			while (srcByte < FCSR_FileSysPointer + (FCSR_SramSectorEnd[i] * BYTE_PER_READ) )
+				*destByte++ = *srcByte++;
+		}
+	}
+
+		// Get SRAM sector regions from header block
+	for (i = 0; i < 4; i++)
+	{
+		if (SramRegionSize[i] == 0)
+		{
+			FCSR_SramSectorStart[i] = NO_SRAM;
+			FCSR_SramSectorEnd[i] = NO_SRAM;
+		}
+	}
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_fcsr = {
+	DEVICE_TYPE_FCSR,	// 'FCSR'
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&FCSR_StartUp,
+	(FN_MEDIUM_ISINSERTED)&FCSR_IsInserted,
+	(FN_MEDIUM_READSECTORS)&FCSR_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&FCSR_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&FCSR_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&FCSR_Shutdown
+} ;
+
+/*-----------------------------------------------------------------
+FCSR_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE FCSR_GetInterface(void) {
+	return &io_fcsr ;
+} ;
+
+#endif // SUPPORT_FCSR
+/*
+	io_fcsr.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for using a GBA Flash Cart and SRAM as a 
+	block device.
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+
+	The file system must be 512 byte aligned, in cart address space.
+	SRAM is supported.
+*/
+
+
+#include "io_fcsr.h"
+
+#ifdef SUPPORT_FCSR
+#include <string.h>
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+#ifdef NDS
+ #define SRAM_START 0x0A000000
+#else
+ #define SRAM_START 0x0E000000
+#endif
+
+#define NO_SRAM 0xFFFFFFFF
+
+#define FCSR 0x52534346
+const char FCSR_LabelString[] = " Chishm FAT";
+
+u8* FCSR_FileSysPointer = 0;
+u8* FCSR_SramSectorPointer[4] = {0,0,0,0};
+u32 FCSR_SramSectorStart[4] = {0,0,0,0};
+u32 FCSR_SramSectorEnd[4] = {0,0,0,0};
+
+/*-----------------------------------------------------------------
+FCSR_IsInserted
+Is a GBA Flash Cart with a valid file system inserted?
+bool return OUT:  true if a GBA FC card is inserted
+-----------------------------------------------------------------*/
+bool FCSR_IsInserted (void) 
+{
+	bool flagFoundFileSys = false;
+
+	u32* fileSysPointer = (u32*)0x08000100;		// Start at beginning of cart address space, offset by expected location of string
+
+	// Search for file system
+	while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)	// Only search while not at end of cart address space
+	{
+		while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
+			fileSysPointer += 0x40;
+		if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
+		{
+			flagFoundFileSys = true;
+		} else {
+			fileSysPointer += 0x80;
+		}
+	}
+
+	return flagFoundFileSys;
+}
+
+
+/*-----------------------------------------------------------------
+FCSR_ClearStatus
+Finish any pending operations
+bool return OUT:  always true for GBA FC
+-----------------------------------------------------------------*/
+bool FCSR_ClearStatus (void) 
+{
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+FCSR_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on Flash Cart to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FCSR_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{	
+	int i;
+	bool flagSramSector = false;
+	int numSectors = (numSecs > 0 ? numSecs : 256);
+	int readLength = numSectors * BYTE_PER_READ;
+	u8* src;;
+	u8* dst;
+
+	// Find which region this read is in
+	for (i = 0; (i < 4) && !flagSramSector; i++)
+	{
+		if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
+		{
+			flagSramSector = true;
+			break;
+		}
+	}
+
+	// Make sure read will be completely in SRAM range if it is partially there
+	if ( flagSramSector && ((sector + numSectors) > FCSR_SramSectorEnd[i]))
+		return false;
+
+	// Copy data to buffer
+	if (flagSramSector)
+	{
+		src = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
+	} else {
+		src = FCSR_FileSysPointer + sector * BYTE_PER_READ;
+	}
+	dst = (u8*)buffer;
+
+	if (flagSramSector)
+	{
+		while (readLength--)
+		{
+			*dst++ = *src++;
+		}
+	} else {	// Reading from Cart ROM
+
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+  #ifdef ARM9
+		DC_FlushRange( buffer, readLength);
+  #endif	// ARM9
+		DMA3_SRC = (u32)src;
+		DMA3_DEST = (u32)buffer;
+		DMA3_CR = (readLength >> 1) | DMA_COPY_HALFWORDS;
+ #else	// ! NDS
+		DMA3COPY ( src, buffer, (readLength >> 1) | DMA16 | DMA_ENABLE);
+ #endif	// NDS
+#else	// !_CF_USE_DMA
+		memcpy (buffer, src, readLength);
+#endif	// _CF_USE_DMA
+
+	}	// if (flagSramSector)
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on Flash Cart to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool FCSR_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	bool flagSramSector = false;
+	int writeLength = (numSecs > 0 ? numSecs : 256) * BYTE_PER_READ;
+	u8* src = (u8*) buffer;
+	u8* dst;
+
+	// Find which region this sector belongs in
+	for (i = 0; (i < 4) && !flagSramSector; i++)
+	{
+		if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
+		{
+			flagSramSector = true;
+			break;
+		}
+	}
+
+	if (!flagSramSector)
+		return false;
+
+	// Entire write must be within an SRAM region
+	if ((sector + (numSecs > 0 ? numSecs : 256)) > FCSR_SramSectorEnd[i])
+		return false;
+
+	// Copy data to SRAM
+	dst = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
+	while (writeLength--)
+	{
+		*dst++ = *src++;
+	}
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_Shutdown
+unload the Flash Cart interface
+-----------------------------------------------------------------*/
+bool FCSR_Shutdown(void) 
+{
+	int i;
+	if (FCSR_ClearStatus() == false)
+		return false;
+
+	FCSR_FileSysPointer = 0;
+	
+	for (i=0; i < 4; i++)
+	{
+		FCSR_SramSectorPointer[i] = 0;
+		FCSR_SramSectorStart[i] = 0;
+		FCSR_SramSectorEnd[i] = 0;
+	}
+	return true;
+}
+
+/*-----------------------------------------------------------------
+FCSR_StartUp
+initializes the Flash Cart interface, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool FCSR_StartUp(void)
+{
+	bool flagFoundFileSys = false;
+	int i;
+	int SramRegionSize[4];
+	u8* srcByte;
+	u8* destByte;
+
+	u32* fileSysPointer = (u32*)0x08000100;		// Start at beginning of cart address space, offset by expected location of string
+
+	// Search for file system
+	while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)	// Only search while not at end of cart address space
+	{
+		while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
+			fileSysPointer += 0x40;
+		if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
+		{
+			flagFoundFileSys = true;
+		} else {
+			fileSysPointer += 0x80;
+		}
+	}
+
+	if (!flagFoundFileSys)
+		return false;
+
+	// Flash cart file system pointer has been found
+	FCSR_FileSysPointer = (u8*)(fileSysPointer - 0x40);
+
+	// Get SRAM sector regions from header block
+	for (i = 0; i < 4; i++)
+	{
+		FCSR_SramSectorStart[i] = fileSysPointer[i+4];	
+		SramRegionSize[i] = fileSysPointer[i+8];
+		FCSR_SramSectorEnd[i] = FCSR_SramSectorStart[i] + SramRegionSize[i];
+	}
+	
+	// Calculate SRAM region pointers
+	FCSR_SramSectorPointer[0] = (u8*)(SRAM_START + 4);
+	for (i = 1; i < 4; i++)
+	{
+		FCSR_SramSectorPointer[i] = FCSR_SramSectorPointer[i-1] + (SramRegionSize[i-1] * BYTE_PER_READ);
+	}
+
+	// Initialise SRAM with overlay if it hasn't been done so
+	if ( (*((u8*)SRAM_START) != 'F')  || (*((u8*)(SRAM_START+1)) != 'C') || (*((u8*)(SRAM_START+2)) != 'S') || (*((u8*)(SRAM_START+3)) != 'R') )
+	{
+		*((u8*)SRAM_START) = 'F';
+		*((u8*)(SRAM_START+1)) = 'C';
+		*((u8*)(SRAM_START+2)) = 'S';
+		*((u8*)(SRAM_START+3)) = 'R';
+
+		for (i = 0; i < 4; i++)
+		{
+			srcByte = FCSR_FileSysPointer + (FCSR_SramSectorStart[i] * BYTE_PER_READ);
+			destByte = FCSR_SramSectorPointer[i];
+			while (srcByte < FCSR_FileSysPointer + (FCSR_SramSectorEnd[i] * BYTE_PER_READ) )
+				*destByte++ = *srcByte++;
+		}
+	}
+
+		// Get SRAM sector regions from header block
+	for (i = 0; i < 4; i++)
+	{
+		if (SramRegionSize[i] == 0)
+		{
+			FCSR_SramSectorStart[i] = NO_SRAM;
+			FCSR_SramSectorEnd[i] = NO_SRAM;
+		}
+	}
+
+	return true;
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_fcsr = {
+	DEVICE_TYPE_FCSR,	// 'FCSR'
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&FCSR_StartUp,
+	(FN_MEDIUM_ISINSERTED)&FCSR_IsInserted,
+	(FN_MEDIUM_READSECTORS)&FCSR_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&FCSR_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&FCSR_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&FCSR_Shutdown
+} ;
+
+/*-----------------------------------------------------------------
+FCSR_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE FCSR_GetInterface(void) {
+	return &io_fcsr ;
+} ;
+
+#endif // SUPPORT_FCSR


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,48 @@
+/*
+	io_fcsr.h 
+
+	Hardware Routines for using a GBA Flash Cart with SRAM
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_FCSR_H
+#define IO_FCSR_H
+
+// 'FCSR'
+#define DEVICE_TYPE_FCSR 0x52534346
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE FCSR_GetInterface(void) ;
+
+#endif	// define IO_FCSR_H
+/*
+	io_fcsr.h 
+
+	Hardware Routines for using a GBA Flash Cart with SRAM
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_FCSR_H
+#define IO_FCSR_H
+
+// 'FCSR'
+#define DEVICE_TYPE_FCSR 0x52534346
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE FCSR_GetInterface(void) ;
+
+#endif	// define IO_FCSR_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_fcsr.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,734 @@
+/*
+	io_m3cf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the M3 Perfect CF Adapter
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_m3cf.h"
+
+#ifdef SUPPORT_M3CF
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// CF Addresses & Commands
+
+#define GAME_PAK		0x08000000			// Game pack start address
+
+// GBAMP CF Addresses
+#define M3_REG_STS		*(vu16*)(GAME_PAK + 0x000C0000)	// Status of the CF Card / Device control
+#define M3_REG_CMD		*(vu16*)(GAME_PAK + 0x008E0000)	// Commands sent to control chip and status return
+#define M3_REG_ERR		*(vu16*)(GAME_PAK + 0x00820000)	// Errors / Features
+
+#define M3_REG_SEC		*(vu16*)(GAME_PAK + 0x00840000)	// Number of sector to transfer
+#define M3_REG_LBA1		*(vu16*)(GAME_PAK + 0x00860000)	// 1st byte of sector address
+#define M3_REG_LBA2		*(vu16*)(GAME_PAK + 0x00880000)	// 2nd byte of sector address
+#define M3_REG_LBA3		*(vu16*)(GAME_PAK + 0x008A0000)	// 3rd byte of sector address
+#define M3_REG_LBA4		*(vu16*)(GAME_PAK + 0x008C0000)	// last nibble of sector address | 0xE0
+
+#define M3_DATA			(vu16*)(GAME_PAK + 0x00800000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED		0x50
+#define CF_STS_REMOVED		0x00
+#define CF_STS_READY		0x58
+
+#define CF_STS_DRQ			0x08
+#define CF_STS_BUSY			0x80
+
+// CF Card commands
+#define CF_CMD_LBA			0xE0
+#define CF_CMD_READ			0x20
+#define CF_CMD_WRITE		0x30
+
+#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+
+
+/*-----------------------------------------------------------------
+M3CF_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool M3CF_IsInserted (void) 
+{
+	// Change register, then check if value did change
+	M3_REG_STS = CF_STS_INSERTED;
+	return ((M3_REG_STS & 0xff) == CF_STS_INSERTED);
+}
+
+
+/*-----------------------------------------------------------------
+M3CF_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool M3CF_ClearStatus (void) 
+{
+	int i;
+	
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3CF_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3CF_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to read
+	M3_REG_SEC = numSecs;	
+	
+	// Set read sector
+	M3_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	M3_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	M3_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	M3_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to read
+	M3_REG_CMD = CF_CMD_READ;
+	
+	
+	while (j--)
+	{
+		// Wait until card is ready for reading
+		i = 0;
+		while (((M3_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Read data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)M3_DATA;
+		DMA3_DEST = (u32)buff;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
+ #else
+		DMA3COPY ( M3_DATA, buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *M3_DATA;
+				*buff_u8++ = temp & 0xFF;
+				*buff_u8++ = temp >> 8;
+			}
+		} else {
+		while(i--)
+			*buff++ = *M3_DATA; 
+		}
+#else
+		i=256;
+		while(i--)
+			*buff++ = *M3_DATA; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+
+	return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+M3CF_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3CF_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to write
+	M3_REG_SEC = numSecs;	
+	
+	// Set write sector
+	M3_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	M3_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	M3_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	M3_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to write
+	M3_REG_CMD = CF_CMD_WRITE;
+	
+	while (j--)
+	{
+		// Wait until card is ready for writing
+		i = 0;
+		while (((M3_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Write data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)buff;
+		DMA3_DEST = (u32)M3_DATA;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
+ #else
+		DMA3COPY( buff, M3_DATA, 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *buff_u8++;
+				temp |= *buff_u8++ << 8;
+				*M3_DATA = temp;
+			}
+		} else {
+		while(i--)
+			*M3_DATA = *buff++; 
+		}
+#else
+		i=256;
+		while(i--)
+			*M3_DATA = *buff++; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3_Unlock
+Returns true if M3 was unlocked, false if failed
+Added by MightyMax
+-----------------------------------------------------------------*/
+bool M3_Unlock(void) 
+{
+	// run unlock sequence
+	volatile unsigned short tmp ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08E00002 ;
+	tmp = *(volatile unsigned short *)0x0800000E ;
+	tmp = *(volatile unsigned short *)0x08801FFC ;
+	tmp = *(volatile unsigned short *)0x0800104A ;
+	tmp = *(volatile unsigned short *)0x08800612 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08801B66 ;
+	tmp = *(volatile unsigned short *)0x08800006 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	// test that we have register access
+	tmp = M3_REG_LBA1;
+	M3_REG_LBA1 = (~tmp & 0xFF);
+	tmp = (~tmp & 0xFF);
+	// did it change?
+	return (M3_REG_LBA1 == tmp) ;
+}
+
+bool M3CF_Shutdown(void) {
+	return M3CF_ClearStatus() ;
+} ;
+
+bool M3CF_StartUp(void) {
+	return M3_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_m3cf = {
+	DEVICE_TYPE_M3CF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&M3CF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&M3CF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&M3CF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&M3CF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&M3CF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&M3CF_Shutdown
+} ;
+
+
+LPIO_INTERFACE M3CF_GetInterface(void) {
+	return &io_m3cf ;
+} ;
+
+#endif // SUPPORT_M3CF
+/*
+	io_m3cf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the M3 Perfect CF Adapter
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_m3cf.h"
+
+#ifdef SUPPORT_M3CF
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// CF Addresses & Commands
+
+#define GAME_PAK		0x08000000			// Game pack start address
+
+// GBAMP CF Addresses
+#define M3_REG_STS		*(vu16*)(GAME_PAK + 0x000C0000)	// Status of the CF Card / Device control
+#define M3_REG_CMD		*(vu16*)(GAME_PAK + 0x008E0000)	// Commands sent to control chip and status return
+#define M3_REG_ERR		*(vu16*)(GAME_PAK + 0x00820000)	// Errors / Features
+
+#define M3_REG_SEC		*(vu16*)(GAME_PAK + 0x00840000)	// Number of sector to transfer
+#define M3_REG_LBA1		*(vu16*)(GAME_PAK + 0x00860000)	// 1st byte of sector address
+#define M3_REG_LBA2		*(vu16*)(GAME_PAK + 0x00880000)	// 2nd byte of sector address
+#define M3_REG_LBA3		*(vu16*)(GAME_PAK + 0x008A0000)	// 3rd byte of sector address
+#define M3_REG_LBA4		*(vu16*)(GAME_PAK + 0x008C0000)	// last nibble of sector address | 0xE0
+
+#define M3_DATA			(vu16*)(GAME_PAK + 0x00800000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED		0x50
+#define CF_STS_REMOVED		0x00
+#define CF_STS_READY		0x58
+
+#define CF_STS_DRQ			0x08
+#define CF_STS_BUSY			0x80
+
+// CF Card commands
+#define CF_CMD_LBA			0xE0
+#define CF_CMD_READ			0x20
+#define CF_CMD_WRITE		0x30
+
+#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+
+
+/*-----------------------------------------------------------------
+M3CF_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool M3CF_IsInserted (void) 
+{
+	// Change register, then check if value did change
+	M3_REG_STS = CF_STS_INSERTED;
+	return ((M3_REG_STS & 0xff) == CF_STS_INSERTED);
+}
+
+
+/*-----------------------------------------------------------------
+M3CF_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool M3CF_ClearStatus (void) 
+{
+	int i;
+	
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3CF_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3CF_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to read
+	M3_REG_SEC = numSecs;	
+	
+	// Set read sector
+	M3_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	M3_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	M3_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	M3_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to read
+	M3_REG_CMD = CF_CMD_READ;
+	
+	
+	while (j--)
+	{
+		// Wait until card is ready for reading
+		i = 0;
+		while (((M3_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Read data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)M3_DATA;
+		DMA3_DEST = (u32)buff;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
+ #else
+		DMA3COPY ( M3_DATA, buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *M3_DATA;
+				*buff_u8++ = temp & 0xFF;
+				*buff_u8++ = temp >> 8;
+			}
+		} else {
+		while(i--)
+			*buff++ = *M3_DATA; 
+		}
+#else
+		i=256;
+		while(i--)
+			*buff++ = *M3_DATA; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+
+	return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+M3CF_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3CF_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((M3_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(M3_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to write
+	M3_REG_SEC = numSecs;	
+	
+	// Set write sector
+	M3_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	M3_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	M3_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	M3_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to write
+	M3_REG_CMD = CF_CMD_WRITE;
+	
+	while (j--)
+	{
+		// Wait until card is ready for writing
+		i = 0;
+		while (((M3_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Write data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)buff;
+		DMA3_DEST = (u32)M3_DATA;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
+ #else
+		DMA3COPY( buff, M3_DATA, 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *buff_u8++;
+				temp |= *buff_u8++ << 8;
+				*M3_DATA = temp;
+			}
+		} else {
+		while(i--)
+			*M3_DATA = *buff++; 
+		}
+#else
+		i=256;
+		while(i--)
+			*M3_DATA = *buff++; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3_Unlock
+Returns true if M3 was unlocked, false if failed
+Added by MightyMax
+-----------------------------------------------------------------*/
+bool M3_Unlock(void) 
+{
+	// run unlock sequence
+	volatile unsigned short tmp ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08E00002 ;
+	tmp = *(volatile unsigned short *)0x0800000E ;
+	tmp = *(volatile unsigned short *)0x08801FFC ;
+	tmp = *(volatile unsigned short *)0x0800104A ;
+	tmp = *(volatile unsigned short *)0x08800612 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08801B66 ;
+	tmp = *(volatile unsigned short *)0x08800006 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	// test that we have register access
+	tmp = M3_REG_LBA1;
+	M3_REG_LBA1 = (~tmp & 0xFF);
+	tmp = (~tmp & 0xFF);
+	// did it change?
+	return (M3_REG_LBA1 == tmp) ;
+}
+
+bool M3CF_Shutdown(void) {
+	return M3CF_ClearStatus() ;
+} ;
+
+bool M3CF_StartUp(void) {
+	return M3_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_m3cf = {
+	DEVICE_TYPE_M3CF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&M3CF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&M3CF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&M3CF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&M3CF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&M3CF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&M3CF_Shutdown
+} ;
+
+
+LPIO_INTERFACE M3CF_GetInterface(void) {
+	return &io_m3cf ;
+} ;
+
+#endif // SUPPORT_M3CF


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,50 @@
+/*
+	io_m3cf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the M3 CF
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_M3CF_H
+#define IO_M3CF_H
+
+// 'M3CF'
+#define DEVICE_TYPE_M3CF 0x4643334D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE M3CF_GetInterface(void) ;
+
+#endif	// define IO_M3CF_H
+/*
+	io_m3cf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the M3 CF
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_M3CF_H
+#define IO_M3CF_H
+
+// 'M3CF'
+#define DEVICE_TYPE_M3CF 0x4643334D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE M3CF_GetInterface(void) ;
+
+#endif	// define IO_M3CF_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3cf.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,750 @@
+/*
+	io_m3sd.c based on io_m3cf.c by SaTa.
+
+	io_m3cf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the M3 Perfect CF Adapter
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_m3sd.h"
+
+#ifdef SUPPORT_M3SD
+
+//SD dir control bit cmddir=bit0 clken=bit1
+//output
+#define SDDIR			(*(volatile u16*)0x8800000)
+
+//SD send get control bit send=bit0 get=bit1
+//output
+#define SDCON			(*(volatile u16*)0x9800000)
+
+//SD output data obyte[7:0]=AD[7:0]
+//output
+#define SDODA			(*(volatile u16*)0x9000000)
+
+//SD input data AD[7:0]=ibyte[7:0]
+//input
+#define SDIDA			(*(volatile u16*)0x9000000)
+
+//readsector data1
+#define SDIDA1			(*(volatile u16*)0x9200000)
+
+//readsector data2
+#define SDIDA2			(*(volatile u16*)0x9400000)
+
+//readsector data3
+#define SDIDA3			(*(volatile u16*)0x9600000)
+
+//SD stutas cmdneg=bit0 cmdpos=bit1 issend=bit2 isget=bit3
+//input
+#define SDSTA			(*(volatile u16*)0x9800000)
+
+//#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+#define CARD_TIMEOUT	(500*100)		// M3SD timeout nomal:500
+
+//======================================================
+bool M3SD_read1sector(u32 sectorn,u32 TAddr)
+{
+	u32 i;
+	int w;
+	
+	SDCON=0x8;		//	bit3:\x83R\x83}\x83\x93\x83h\x83\x82\x81[\x83h\x81H
+	SDIDA1=0x40+17;		//	\x83R\x83}\x83\x93\x83h CMD17
+	SDIDA2=(sectorn>>7);//	\x83Z\x83N\x83^H 9\x83r\x83b\x83g=\x83A\x83h\x83\x8C\x83XH \x82P\x82U\x83r\x83b\x83g
+	SDIDA3=(sectorn<<9);//	\x83Z\x83N\x83^L 7\x83r\x83b\x83g=\x83A\x83h\x83\x8C\x83XL \x82P\x82U\x83r\x83b\x83g
+	SDDIR=0x29;		//	\x83R\x83}\x83\x93\x83h\x91\x97\x90M\x81H
+	i=0;
+
+	while ( ((SDSTA&0x01) != 0x01)&&(i < CARD_TIMEOUT) )
+	{
+		i++;
+	}
+	SDDIR=0x09;
+	i=0;
+	SDDIR=0x49;
+	while ( ((SDSTA&0x40) != 0x40)&&(i < CARD_TIMEOUT) )
+	{
+		i++;
+	}
+	SDDIR=0x09;
+		
+	SDDIR=0x8;//cmd input clken=0 datadir input clock=0
+	SDCON=0x4;//send=0 get=0 en25=1 cmd1=0
+
+	w = SDDIR;
+	for(w=0;w<0x100;w++)
+	{
+		u16 d16;
+		u8 *d8=(u8 *)&d16;
+//		*(u16*)(TAddr+w*2) = SDDIR;	//	16bit
+		d16 = SDDIR;	//	16bit
+		*(u8 *)(TAddr+w*2) =d8[0];
+		*(u8 *)(TAddr+w*2+1) =d8[1];
+		
+	}
+	w = SDDIR;
+	w = SDDIR;
+	
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+	
+} 
+//==================================================
+
+
+//======================================================
+void SD_crc16(u16* buff,u16 num,u16* crc16buff);
+void SD_data_write(u16 *buff,u16* crc16buff);
+
+u16  Hal4ATA_StatusByte;
+
+void Hal4ATA_GetStatus(void)
+{
+	Hal4ATA_StatusByte = SDSTA;
+}
+
+bool Hal4ATA_WaitOnBusy(void)
+{
+	Hal4ATA_GetStatus();
+	while ( (Hal4ATA_StatusByte & 0x01) != 0x1)
+	{
+		Hal4ATA_GetStatus();
+	}
+	return TRUE;
+}
+
+bool Hal4ATA_WaitOnBusyNDrdy(void)
+{
+	Hal4ATA_GetStatus();
+	while ( (Hal4ATA_StatusByte&0x40) !=0x40)
+	{
+		Hal4ATA_GetStatus();
+	}
+	return TRUE;
+}
+
+
+void SendCommand(u16 command, u32 sectorn)
+{
+	SDCON=0x8;
+	SDIDA1=0x40+command;
+	SDIDA2=(sectorn>>7);
+	SDIDA3=(sectorn<<9);
+
+	SDDIR=0x29;
+	Hal4ATA_WaitOnBusy();
+	SDDIR=0x09;
+}
+
+
+#define DMA3SAD      *(u32*)0x040000D4
+#define DMA3DAD      *(u32*)0x040000D8
+#define DMA3CNT      *(u32*)0x040000DC
+
+void DMA3(u32 src, u32 dst, u32 cnt)
+{
+	DMA3SAD=src;
+	DMA3DAD=dst;
+	DMA3CNT=cnt;
+}
+
+
+
+void PassRespond(u32 num)
+{
+	u32 i,dmanum;
+	
+	dmanum=(64+(num<<3))>>2;
+	SDDIR=0x8;
+	SDCON=0x4;
+	DMA3(0x8800000,(u32)&i,0x80400000+dmanum);
+}
+
+//bool M3SD_write1sector(u32 sectorn,u16 * p)
+bool M3SD_write1sector(u32 sectorn,u32 p)
+{
+	u16 crc[4];
+
+	SendCommand(24,sectorn);
+	PassRespond(6);
+
+	SDDIR=0x4;
+	SDCON=0x0;
+
+	SD_crc16((u16 *)p,512,crc);
+	SD_data_write((u16 *)p,crc);
+	return true;
+} 
+//==================================================
+
+
+// GBAMP CF Addresses
+
+#define M3_REG_STS		*(vu16*)(0x09800000)	// Status of the CF Card / Device control
+
+#define M3_DATA			(vu16*)(0x08800000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED1		0x20
+#define CF_STS_INSERTED2		0x30
+
+/*-----------------------------------------------------------------
+M3SD_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool M3SD_IsInserted (void) 
+{
+	int i;
+	u16 sta;
+	// Change register, then check if value did change
+	M3_REG_STS = CF_STS_INSERTED1;
+
+	for(i=0;i<CARD_TIMEOUT;i++)
+	{
+		sta=M3_REG_STS;
+		if((sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2))
+		{
+			return true;
+			//break;
+		}
+	}
+	return false;
+
+//	return ( (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2) );
+//	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3SD_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool M3SD_ClearStatus (void) 
+{
+
+//	int i=SDDIR;
+	int i;
+	u16 sta;
+
+	i = 0;
+	M3_REG_STS = CF_STS_INSERTED1;
+	while (i < CARD_TIMEOUT)
+	{
+		sta=M3_REG_STS;
+		if(  (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2)  )break;
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3SD_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3SD_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+
+
+	//void M3SD_read1sector(u32 sectorn,u32 TAddr)
+	bool r=true;
+	int i;
+	for(i=0;i<numSecs;i++)
+	{
+		if(M3SD_read1sector(i + sector , 512*i + (u32) buffer )==false)
+		{
+			r=false;
+			break;
+		}
+	}
+	return r;
+
+}
+
+
+
+/*-----------------------------------------------------------------
+M3SD_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3SD_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+
+	bool r=true;
+	int i;
+	for(i=0;i<numSecs;i++)
+	{
+		if(M3SD_write1sector(i + sector , 512*i + (u32) buffer )==false)
+		{
+			r=false;
+			break;
+		}
+	}
+	return r;
+
+//	return false;
+
+
+}
+
+
+/*-----------------------------------------------------------------
+M3_Unlock
+Returns true if M3 was unlocked, false if failed
+Added by MightyMax
+-----------------------------------------------------------------*/
+bool M3SD_Unlock(void) 
+{
+
+	// run unlock sequence
+	volatile unsigned short tmp ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08E00002 ;
+	tmp = *(volatile unsigned short *)0x0800000E ;
+	tmp = *(volatile unsigned short *)0x08801FFC ;
+	tmp = *(volatile unsigned short *)0x0800104A ;
+	tmp = *(volatile unsigned short *)0x08800612 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08801B66 ;
+	tmp = *(volatile unsigned short *)0x08800006 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	// test that we have register access
+	vu16 sta;
+	sta=M3_REG_STS;
+	sta=M3_REG_STS;
+	if(  (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2)  )return true;
+
+	return false;
+}
+
+bool M3SD_Shutdown(void) {
+	return M3SD_ClearStatus() ;
+} ;
+
+bool M3SD_StartUp(void) {
+	return M3SD_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_m3sd = {
+	DEVICE_TYPE_M3SD,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&M3SD_StartUp,
+	(FN_MEDIUM_ISINSERTED)&M3SD_IsInserted,
+	(FN_MEDIUM_READSECTORS)&M3SD_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&M3SD_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&M3SD_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&M3SD_Shutdown
+} ;
+
+
+LPIO_INTERFACE M3SD_GetInterface(void) {
+	return &io_m3sd ;
+} ;
+
+#endif // SUPPORT_M3CF
+/*
+	io_m3sd.c based on io_m3cf.c by SaTa.
+
+	io_m3cf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the M3 Perfect CF Adapter
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_m3sd.h"
+
+#ifdef SUPPORT_M3SD
+
+//SD dir control bit cmddir=bit0 clken=bit1
+//output
+#define SDDIR			(*(volatile u16*)0x8800000)
+
+//SD send get control bit send=bit0 get=bit1
+//output
+#define SDCON			(*(volatile u16*)0x9800000)
+
+//SD output data obyte[7:0]=AD[7:0]
+//output
+#define SDODA			(*(volatile u16*)0x9000000)
+
+//SD input data AD[7:0]=ibyte[7:0]
+//input
+#define SDIDA			(*(volatile u16*)0x9000000)
+
+//readsector data1
+#define SDIDA1			(*(volatile u16*)0x9200000)
+
+//readsector data2
+#define SDIDA2			(*(volatile u16*)0x9400000)
+
+//readsector data3
+#define SDIDA3			(*(volatile u16*)0x9600000)
+
+//SD stutas cmdneg=bit0 cmdpos=bit1 issend=bit2 isget=bit3
+//input
+#define SDSTA			(*(volatile u16*)0x9800000)
+
+//#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+#define CARD_TIMEOUT	(500*100)		// M3SD timeout nomal:500
+
+//======================================================
+bool M3SD_read1sector(u32 sectorn,u32 TAddr)
+{
+	u32 i;
+	int w;
+	
+	SDCON=0x8;		//	bit3:\x83R\x83}\x83\x93\x83h\x83\x82\x81[\x83h\x81H
+	SDIDA1=0x40+17;		//	\x83R\x83}\x83\x93\x83h CMD17
+	SDIDA2=(sectorn>>7);//	\x83Z\x83N\x83^H 9\x83r\x83b\x83g=\x83A\x83h\x83\x8C\x83XH \x82P\x82U\x83r\x83b\x83g
+	SDIDA3=(sectorn<<9);//	\x83Z\x83N\x83^L 7\x83r\x83b\x83g=\x83A\x83h\x83\x8C\x83XL \x82P\x82U\x83r\x83b\x83g
+	SDDIR=0x29;		//	\x83R\x83}\x83\x93\x83h\x91\x97\x90M\x81H
+	i=0;
+
+	while ( ((SDSTA&0x01) != 0x01)&&(i < CARD_TIMEOUT) )
+	{
+		i++;
+	}
+	SDDIR=0x09;
+	i=0;
+	SDDIR=0x49;
+	while ( ((SDSTA&0x40) != 0x40)&&(i < CARD_TIMEOUT) )
+	{
+		i++;
+	}
+	SDDIR=0x09;
+		
+	SDDIR=0x8;//cmd input clken=0 datadir input clock=0
+	SDCON=0x4;//send=0 get=0 en25=1 cmd1=0
+
+	w = SDDIR;
+	for(w=0;w<0x100;w++)
+	{
+		u16 d16;
+		u8 *d8=(u8 *)&d16;
+//		*(u16*)(TAddr+w*2) = SDDIR;	//	16bit
+		d16 = SDDIR;	//	16bit
+		*(u8 *)(TAddr+w*2) =d8[0];
+		*(u8 *)(TAddr+w*2+1) =d8[1];
+		
+	}
+	w = SDDIR;
+	w = SDDIR;
+	
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+	
+} 
+//==================================================
+
+
+//======================================================
+void SD_crc16(u16* buff,u16 num,u16* crc16buff);
+void SD_data_write(u16 *buff,u16* crc16buff);
+
+u16  Hal4ATA_StatusByte;
+
+void Hal4ATA_GetStatus(void)
+{
+	Hal4ATA_StatusByte = SDSTA;
+}
+
+bool Hal4ATA_WaitOnBusy(void)
+{
+	Hal4ATA_GetStatus();
+	while ( (Hal4ATA_StatusByte & 0x01) != 0x1)
+	{
+		Hal4ATA_GetStatus();
+	}
+	return TRUE;
+}
+
+bool Hal4ATA_WaitOnBusyNDrdy(void)
+{
+	Hal4ATA_GetStatus();
+	while ( (Hal4ATA_StatusByte&0x40) !=0x40)
+	{
+		Hal4ATA_GetStatus();
+	}
+	return TRUE;
+}
+
+
+void SendCommand(u16 command, u32 sectorn)
+{
+	SDCON=0x8;
+	SDIDA1=0x40+command;
+	SDIDA2=(sectorn>>7);
+	SDIDA3=(sectorn<<9);
+
+	SDDIR=0x29;
+	Hal4ATA_WaitOnBusy();
+	SDDIR=0x09;
+}
+
+
+#define DMA3SAD      *(u32*)0x040000D4
+#define DMA3DAD      *(u32*)0x040000D8
+#define DMA3CNT      *(u32*)0x040000DC
+
+void DMA3(u32 src, u32 dst, u32 cnt)
+{
+	DMA3SAD=src;
+	DMA3DAD=dst;
+	DMA3CNT=cnt;
+}
+
+
+
+void PassRespond(u32 num)
+{
+	u32 i,dmanum;
+	
+	dmanum=(64+(num<<3))>>2;
+	SDDIR=0x8;
+	SDCON=0x4;
+	DMA3(0x8800000,(u32)&i,0x80400000+dmanum);
+}
+
+//bool M3SD_write1sector(u32 sectorn,u16 * p)
+bool M3SD_write1sector(u32 sectorn,u32 p)
+{
+	u16 crc[4];
+
+	SendCommand(24,sectorn);
+	PassRespond(6);
+
+	SDDIR=0x4;
+	SDCON=0x0;
+
+	SD_crc16((u16 *)p,512,crc);
+	SD_data_write((u16 *)p,crc);
+	return true;
+} 
+//==================================================
+
+
+// GBAMP CF Addresses
+
+#define M3_REG_STS		*(vu16*)(0x09800000)	// Status of the CF Card / Device control
+
+#define M3_DATA			(vu16*)(0x08800000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED1		0x20
+#define CF_STS_INSERTED2		0x30
+
+/*-----------------------------------------------------------------
+M3SD_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool M3SD_IsInserted (void) 
+{
+	int i;
+	u16 sta;
+	// Change register, then check if value did change
+	M3_REG_STS = CF_STS_INSERTED1;
+
+	for(i=0;i<CARD_TIMEOUT;i++)
+	{
+		sta=M3_REG_STS;
+		if((sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2))
+		{
+			return true;
+			//break;
+		}
+	}
+	return false;
+
+//	return ( (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2) );
+//	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3SD_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool M3SD_ClearStatus (void) 
+{
+
+//	int i=SDDIR;
+	int i;
+	u16 sta;
+
+	i = 0;
+	M3_REG_STS = CF_STS_INSERTED1;
+	while (i < CARD_TIMEOUT)
+	{
+		sta=M3_REG_STS;
+		if(  (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2)  )break;
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+M3SD_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3SD_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+
+
+	//void M3SD_read1sector(u32 sectorn,u32 TAddr)
+	bool r=true;
+	int i;
+	for(i=0;i<numSecs;i++)
+	{
+		if(M3SD_read1sector(i + sector , 512*i + (u32) buffer )==false)
+		{
+			r=false;
+			break;
+		}
+	}
+	return r;
+
+}
+
+
+
+/*-----------------------------------------------------------------
+M3SD_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool M3SD_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+
+	bool r=true;
+	int i;
+	for(i=0;i<numSecs;i++)
+	{
+		if(M3SD_write1sector(i + sector , 512*i + (u32) buffer )==false)
+		{
+			r=false;
+			break;
+		}
+	}
+	return r;
+
+//	return false;
+
+
+}
+
+
+/*-----------------------------------------------------------------
+M3_Unlock
+Returns true if M3 was unlocked, false if failed
+Added by MightyMax
+-----------------------------------------------------------------*/
+bool M3SD_Unlock(void) 
+{
+
+	// run unlock sequence
+	volatile unsigned short tmp ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08E00002 ;
+	tmp = *(volatile unsigned short *)0x0800000E ;
+	tmp = *(volatile unsigned short *)0x08801FFC ;
+	tmp = *(volatile unsigned short *)0x0800104A ;
+	tmp = *(volatile unsigned short *)0x08800612 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	tmp = *(volatile unsigned short *)0x08801B66 ;
+	tmp = *(volatile unsigned short *)0x08800006 ;
+	tmp = *(volatile unsigned short *)0x08000000 ;
+	// test that we have register access
+	vu16 sta;
+	sta=M3_REG_STS;
+	sta=M3_REG_STS;
+	if(  (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2)  )return true;
+
+	return false;
+}
+
+bool M3SD_Shutdown(void) {
+	return M3SD_ClearStatus() ;
+} ;
+
+bool M3SD_StartUp(void) {
+	return M3SD_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_m3sd = {
+	DEVICE_TYPE_M3SD,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&M3SD_StartUp,
+	(FN_MEDIUM_ISINSERTED)&M3SD_IsInserted,
+	(FN_MEDIUM_READSECTORS)&M3SD_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&M3SD_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&M3SD_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&M3SD_Shutdown
+} ;
+
+
+LPIO_INTERFACE M3SD_GetInterface(void) {
+	return &io_m3sd ;
+} ;
+
+#endif // SUPPORT_M3CF


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,50 @@
+/*
+	io_m3sd.h  by SaTa.
+
+	Hardware Routines for reading an SD card
+	using the M3 SD
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_M3SD_H
+#define IO_M3SD_H
+
+// 'M3SD'
+#define DEVICE_TYPE_M3SD 0x4453334D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE M3SD_GetInterface(void) ;
+
+#endif	// define IO_M3SD_H
+/*
+	io_m3sd.h  by SaTa.
+
+	Hardware Routines for reading an SD card
+	using the M3 SD
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_M3SD_H
+#define IO_M3SD_H
+
+// 'M3SD'
+#define DEVICE_TYPE_M3SD 0x4453334D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE M3SD_GetInterface(void) ;
+
+#endif	// define IO_M3SD_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,392 @@
+	.TEXT
+@	AREA M3SD, CODE, READONLY
+@	ENTRY
+ at -----------------------------------
+@	EXPORT SD_crc16
+@	EXPORT SD_data_write
+
+ at CSYNC	EQU	0x9800000
+ at SDDIR	EQU 0x8800000
+ at SDCON	EQU	0x9800000
+ at SDODA	EQU 0x9000000
+.equ CSYNC,0x9800000
+.equ SDDIR,0x8800000
+.equ SDCON,0x9800000
+.equ SDODA,0x9000000
+
+	.ALIGN
+	.CODE 32
+
+clkout:
+	stmfd   r13!,{r0-r1}
+	ldr     r1,=SDDIR
+	mov     r0,#0x4
+	strh    r0,[r1]
+	mov     r0,r0
+	mov     r0,r0
+	mov     r0,#0xc
+	strh    r0,[r1]
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+clkin:
+	stmfd   r13!,{r0-r1}
+	ldr     r1,=SDDIR
+	mov     r0,#0x0
+	strh    r0,[r1]
+	mov     r0,r0
+	mov     r0,r0
+	mov     r0,#0x8
+	strh    r0,[r1]
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+wait_ready:
+	stmfd   r13!,{r0-r2}
+	mov     r2,#32
+	mov	    r1,#SDODA
+sd_write_loop2:
+	mov	    r0,#0xff @end bit
+	strh    r0,[r1]
+	bl      clkout
+	subs    r2, r2, #1
+	bne     sd_write_loop2
+
+sd_write_busy:
+	bl      clkin
+	ldrh    r0,[r1]   
+	tst	    r0,#0x100
+	beq	    sd_write_busy
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+ at ------void SD_crc16(u16* buff,u16 num,u16* crc16buff)
+
+    .GLOBAL SD_crc16
+
+SD_crc16:
+	stmfd   r13!,{r4-r9}
+	mov	    r9,r2
+
+	mov	    r3,#0  
+	mov	    r4,#0  
+	mov	    r5,#0  
+	mov	    r6,#0  
+
+	ldr	    r7,=0x80808080
+	ldr	    r8,=0x1021
+	mov	    r1,r1,lsl #3
+sd_crc16_loop:
+
+	tst	    r7,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	    r3,r3,lsl #1
+	tst	    r3,#0x10000
+	eorne	r3,r3,r8
+	tst	    r2,r7,lsr #24
+	eorne	r3,r3,r8
+	
+	mov	    r4,r4,lsl #1
+	tst	    r4,#0x10000
+	eorne	r4,r4,r8
+	tst	    r2,r7,lsr #25
+	eorne	r4,r4,r8
+	
+	mov	    r5,r5,lsl #1
+	tst	    r5,#0x10000
+	eorne	r5,r5,r8
+	tst	    r2,r7,lsr #26
+	eorne	r5,r5,r8
+	
+	mov	    r6,r6,lsl #1
+	tst	    r6,#0x10000
+	eorne	r6,r6,r8
+	tst	    r2,r7,lsr #27
+	eorne	r6,r6,r8
+
+	mov	    r7,r7,ror #4
+	subs	r1,r1,#4
+	bne     sd_crc16_loop 
+
+	mov	    r2,r9
+	mov	    r8,#16
+sd_crc16_write_data:
+	mov	    r7,r7,lsl #4
+	tst	    r3,#0x8000
+	orrne   r7,r7,#8
+	tst	    r4,#0x8000
+	orrne   r7,r7,#4
+	tst	    r5,#0x8000
+	orrne   r7,r7,#2
+	tst	    r6,#0x8000
+	orrne   r7,r7,#1
+
+	mov	    r3,r3,lsl #1
+	mov	    r4,r4,lsl #1
+	mov	    r5,r5,lsl #1
+	mov	    r6,r6,lsl #1
+
+	sub	    r8,r8,#1
+	tst	    r8,#1
+	streqb  r7,[r2],#1
+	cmp	    r8,#0
+	bne	    sd_crc16_write_data
+
+	ldmfd   r13!,{r4-r9}
+	bx      r14
+ at ------end-----------------------------------
+
+ at -----------------viod SD_data_write(u16 *buff,u16* crc16buff)-------------------
+    .GLOBAL SD_data_write
+SD_data_write:
+	stmfd   r13!,{r4-r5,r14}
+	mov     r5,#512
+	mov	    r2,#SDODA
+sd_data_write_busy:
+	bl      clkin
+	ldrh    r3,[r2]   
+	tst	    r3,#0x100
+	beq	    sd_data_write_busy
+
+	mov	    r3,#0 @star bit
+	strh    r3,[r2]
+	bl      clkout
+
+sd_data_write_loop:
+	ldrh    r4,[r0],#2
+	mov     r3,r4,lsr#4
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4,lsr#12
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4,lsr#8
+	strh    r3,[r2]
+	bl      clkout
+
+	subs    r5, r5, #2
+	bne     sd_data_write_loop  
+
+	cmp	    r1,#0
+	movne   r0,r1
+	movne   r1,#0
+	movne   r5,#8
+	bne	    sd_data_write_loop
+
+	mov     r5,#32
+sd_data_write_loop2:
+	mov	    r3,#0xff @end bit
+	strh    r3,[r2]
+	bl      clkout
+	subs    r5, r5, #1
+	bne     sd_data_write_loop2
+	
+sd_data_write_busy2:
+	bl      clkin
+	ldrh    r3,[r2]   
+	tst	    r3,#0x100
+	beq	    sd_data_write_busy2
+
+	ldmfd   r13!,{r4-r5,r15}
+ at -----------------end-------------------
+
+	.TEXT
+@	AREA M3SD, CODE, READONLY
+@	ENTRY
+ at -----------------------------------
+@	EXPORT SD_crc16
+@	EXPORT SD_data_write
+
+ at CSYNC	EQU	0x9800000
+ at SDDIR	EQU 0x8800000
+ at SDCON	EQU	0x9800000
+ at SDODA	EQU 0x9000000
+.equ CSYNC,0x9800000
+.equ SDDIR,0x8800000
+.equ SDCON,0x9800000
+.equ SDODA,0x9000000
+
+	.ALIGN
+	.CODE 32
+
+clkout:
+	stmfd   r13!,{r0-r1}
+	ldr     r1,=SDDIR
+	mov     r0,#0x4
+	strh    r0,[r1]
+	mov     r0,r0
+	mov     r0,r0
+	mov     r0,#0xc
+	strh    r0,[r1]
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+clkin:
+	stmfd   r13!,{r0-r1}
+	ldr     r1,=SDDIR
+	mov     r0,#0x0
+	strh    r0,[r1]
+	mov     r0,r0
+	mov     r0,r0
+	mov     r0,#0x8
+	strh    r0,[r1]
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+wait_ready:
+	stmfd   r13!,{r0-r2}
+	mov     r2,#32
+	mov	    r1,#SDODA
+sd_write_loop2:
+	mov	    r0,#0xff @end bit
+	strh    r0,[r1]
+	bl      clkout
+	subs    r2, r2, #1
+	bne     sd_write_loop2
+
+sd_write_busy:
+	bl      clkin
+	ldrh    r0,[r1]   
+	tst	    r0,#0x100
+	beq	    sd_write_busy
+	ldmfd	r13!,{r0-r1}
+	bx      r14
+
+ at ------void SD_crc16(u16* buff,u16 num,u16* crc16buff)
+
+    .GLOBAL SD_crc16
+
+SD_crc16:
+	stmfd   r13!,{r4-r9}
+	mov	    r9,r2
+
+	mov	    r3,#0  
+	mov	    r4,#0  
+	mov	    r5,#0  
+	mov	    r6,#0  
+
+	ldr	    r7,=0x80808080
+	ldr	    r8,=0x1021
+	mov	    r1,r1,lsl #3
+sd_crc16_loop:
+
+	tst	    r7,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	    r3,r3,lsl #1
+	tst	    r3,#0x10000
+	eorne	r3,r3,r8
+	tst	    r2,r7,lsr #24
+	eorne	r3,r3,r8
+	
+	mov	    r4,r4,lsl #1
+	tst	    r4,#0x10000
+	eorne	r4,r4,r8
+	tst	    r2,r7,lsr #25
+	eorne	r4,r4,r8
+	
+	mov	    r5,r5,lsl #1
+	tst	    r5,#0x10000
+	eorne	r5,r5,r8
+	tst	    r2,r7,lsr #26
+	eorne	r5,r5,r8
+	
+	mov	    r6,r6,lsl #1
+	tst	    r6,#0x10000
+	eorne	r6,r6,r8
+	tst	    r2,r7,lsr #27
+	eorne	r6,r6,r8
+
+	mov	    r7,r7,ror #4
+	subs	r1,r1,#4
+	bne     sd_crc16_loop 
+
+	mov	    r2,r9
+	mov	    r8,#16
+sd_crc16_write_data:
+	mov	    r7,r7,lsl #4
+	tst	    r3,#0x8000
+	orrne   r7,r7,#8
+	tst	    r4,#0x8000
+	orrne   r7,r7,#4
+	tst	    r5,#0x8000
+	orrne   r7,r7,#2
+	tst	    r6,#0x8000
+	orrne   r7,r7,#1
+
+	mov	    r3,r3,lsl #1
+	mov	    r4,r4,lsl #1
+	mov	    r5,r5,lsl #1
+	mov	    r6,r6,lsl #1
+
+	sub	    r8,r8,#1
+	tst	    r8,#1
+	streqb  r7,[r2],#1
+	cmp	    r8,#0
+	bne	    sd_crc16_write_data
+
+	ldmfd   r13!,{r4-r9}
+	bx      r14
+ at ------end-----------------------------------
+
+ at -----------------viod SD_data_write(u16 *buff,u16* crc16buff)-------------------
+    .GLOBAL SD_data_write
+SD_data_write:
+	stmfd   r13!,{r4-r5,r14}
+	mov     r5,#512
+	mov	    r2,#SDODA
+sd_data_write_busy:
+	bl      clkin
+	ldrh    r3,[r2]   
+	tst	    r3,#0x100
+	beq	    sd_data_write_busy
+
+	mov	    r3,#0 @star bit
+	strh    r3,[r2]
+	bl      clkout
+
+sd_data_write_loop:
+	ldrh    r4,[r0],#2
+	mov     r3,r4,lsr#4
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4,lsr#12
+	strh    r3,[r2]
+	bl      clkout
+	mov     r3,r4,lsr#8
+	strh    r3,[r2]
+	bl      clkout
+
+	subs    r5, r5, #2
+	bne     sd_data_write_loop  
+
+	cmp	    r1,#0
+	movne   r0,r1
+	movne   r1,#0
+	movne   r5,#8
+	bne	    sd_data_write_loop
+
+	mov     r5,#32
+sd_data_write_loop2:
+	mov	    r3,#0xff @end bit
+	strh    r3,[r2]
+	bl      clkout
+	subs    r5, r5, #1
+	bne     sd_data_write_loop2
+	
+sd_data_write_busy2:
+	bl      clkin
+	ldrh    r3,[r2]   
+	tst	    r3,#0x100
+	beq	    sd_data_write_busy2
+
+	ldmfd   r13!,{r4-r5,r15}
+ at -----------------end-------------------
+

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,714 @@
+/*
+	io_mpcf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_mpcf.h"
+
+#ifdef SUPPORT_MPCF
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// CF Addresses & Commands
+
+#define GAME_PAK		0x08000000			// Game pack start address
+
+// GBAMP CF Addresses
+#define MP_REG_STS		*(vu16*)(GAME_PAK + 0x018C0000)	// Status of the CF Card / Device control
+#define MP_REG_CMD		*(vu16*)(GAME_PAK + 0x010E0000)	// Commands sent to control chip and status return
+#define MP_REG_ERR		*(vu16*)(GAME_PAK + 0x01020000)	// Errors / Features
+
+#define MP_REG_SEC		*(vu16*)(GAME_PAK + 0x01040000)	// Number of sector to transfer
+#define MP_REG_LBA1		*(vu16*)(GAME_PAK + 0x01060000)	// 1st byte of sector address
+#define MP_REG_LBA2		*(vu16*)(GAME_PAK + 0x01080000)	// 2nd byte of sector address
+#define MP_REG_LBA3		*(vu16*)(GAME_PAK + 0x010A0000)	// 3rd byte of sector address
+#define MP_REG_LBA4		*(vu16*)(GAME_PAK + 0x010C0000)	// last nibble of sector address | 0xE0
+
+#define MP_DATA			(vu16*)(GAME_PAK + 0x01000000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED		0x50
+#define CF_STS_REMOVED		0x00
+#define CF_STS_READY		0x58
+
+#define CF_STS_DRQ			0x08
+#define CF_STS_BUSY			0x80
+
+// CF Card commands
+#define CF_CMD_LBA			0xE0
+#define CF_CMD_READ			0x20
+#define CF_CMD_WRITE		0x30
+
+#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+
+
+/*-----------------------------------------------------------------
+MPCF_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool MPCF_IsInserted (void) 
+{
+	// Change register, then check if value did change
+	MP_REG_STS = CF_STS_INSERTED;
+	return ((MP_REG_STS & 0xff) == CF_STS_INSERTED);
+}
+
+
+/*-----------------------------------------------------------------
+MPCF_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool MPCF_ClearStatus (void) 
+{
+	int i;
+	
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+MPCF_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+
+#if (defined _CF_USE_DMA) && (defined NDS) && (defined ARM9)
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to read
+	MP_REG_SEC = numSecs;	
+	
+	// Set read sector
+	MP_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	MP_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	MP_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	MP_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to read
+	MP_REG_CMD = CF_CMD_READ;
+	
+	
+	while (j--)
+	{
+		// Wait until card is ready for reading
+		i = 0;
+		while (((MP_REG_STS & 0xff)!= CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Read data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)MP_DATA;
+		DMA3_DEST = (u32)buff;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
+ #else
+		DMA3COPY ( MP_DATA, buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *MP_DATA;
+				*buff_u8++ = temp & 0xFF;
+				*buff_u8++ = temp >> 8;
+			}
+		} else {
+		while(i--)
+			*buff++ = *MP_DATA; 
+		}
+#else
+		i=256;
+		while(i--)
+			*buff++ = *MP_DATA; 
+#endif
+	}
+#if (defined _CF_USE_DMA) && (defined NDS)
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+MPCF_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to write
+	MP_REG_SEC = numSecs;	
+	
+	// Set write sector
+	MP_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	MP_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	MP_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	MP_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to write
+	MP_REG_CMD = CF_CMD_WRITE;
+	
+	while (j--)
+	{
+		// Wait until card is ready for writing
+		i = 0;
+		while (((MP_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Write data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)buff;
+		DMA3_DEST = (u32)MP_DATA;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
+ #else
+		DMA3COPY( buff, MP_DATA, 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *buff_u8++;
+				temp |= *buff_u8++ << 8;
+				*MP_DATA = temp;
+			}
+		} else {
+		while(i--)
+			*MP_DATA = *buff++; 
+		}
+#else
+		i=256;
+		while(i--)
+			*MP_DATA = *buff++; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	
+	return true;
+}
+
+/*-----------------------------------------------------------------
+MPCF_Shutdown
+unload the GBAMP CF interface
+-----------------------------------------------------------------*/
+bool MPCF_Shutdown(void) 
+{
+	return MPCF_ClearStatus() ;
+}
+
+/*-----------------------------------------------------------------
+MPCF_StartUp
+initializes the CF interface, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool MPCF_StartUp(void)
+{
+	u8 temp = MP_REG_LBA1;
+	MP_REG_LBA1 = (~temp & 0xFF);
+	temp = (~temp & 0xFF);
+	return (MP_REG_LBA1 == temp) ;
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_mpcf = {
+	DEVICE_TYPE_MPCF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&MPCF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&MPCF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&MPCF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&MPCF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&MPCF_Shutdown
+} ;
+
+/*-----------------------------------------------------------------
+MPCF_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE MPCF_GetInterface(void) {
+	return &io_mpcf ;
+} ;
+
+#endif // SUPPORT_MPCF
+/*
+	io_mpcf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_mpcf.h"
+
+#ifdef SUPPORT_MPCF
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_USE_DMA
+ #ifndef NDS
+  #include "gba_dma.h"
+ #else
+  #include <nds/dma.h>
+  #ifdef ARM9
+   #include <nds/arm9/cache.h>
+  #endif
+ #endif
+#endif
+
+//---------------------------------------------------------------
+// CF Addresses & Commands
+
+#define GAME_PAK		0x08000000			// Game pack start address
+
+// GBAMP CF Addresses
+#define MP_REG_STS		*(vu16*)(GAME_PAK + 0x018C0000)	// Status of the CF Card / Device control
+#define MP_REG_CMD		*(vu16*)(GAME_PAK + 0x010E0000)	// Commands sent to control chip and status return
+#define MP_REG_ERR		*(vu16*)(GAME_PAK + 0x01020000)	// Errors / Features
+
+#define MP_REG_SEC		*(vu16*)(GAME_PAK + 0x01040000)	// Number of sector to transfer
+#define MP_REG_LBA1		*(vu16*)(GAME_PAK + 0x01060000)	// 1st byte of sector address
+#define MP_REG_LBA2		*(vu16*)(GAME_PAK + 0x01080000)	// 2nd byte of sector address
+#define MP_REG_LBA3		*(vu16*)(GAME_PAK + 0x010A0000)	// 3rd byte of sector address
+#define MP_REG_LBA4		*(vu16*)(GAME_PAK + 0x010C0000)	// last nibble of sector address | 0xE0
+
+#define MP_DATA			(vu16*)(GAME_PAK + 0x01000000)		// Pointer to buffer of CF data transered from card
+
+// CF Card status
+#define CF_STS_INSERTED		0x50
+#define CF_STS_REMOVED		0x00
+#define CF_STS_READY		0x58
+
+#define CF_STS_DRQ			0x08
+#define CF_STS_BUSY			0x80
+
+// CF Card commands
+#define CF_CMD_LBA			0xE0
+#define CF_CMD_READ			0x20
+#define CF_CMD_WRITE		0x30
+
+#define CARD_TIMEOUT	10000000		// Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+
+
+/*-----------------------------------------------------------------
+MPCF_IsInserted
+Is a compact flash card inserted?
+bool return OUT:  true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool MPCF_IsInserted (void) 
+{
+	// Change register, then check if value did change
+	MP_REG_STS = CF_STS_INSERTED;
+	return ((MP_REG_STS & 0xff) == CF_STS_INSERTED);
+}
+
+
+/*-----------------------------------------------------------------
+MPCF_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT:  true if a CF card is idle
+-----------------------------------------------------------------*/
+bool MPCF_ClearStatus (void) 
+{
+	int i;
+	
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+
+	return true;
+}
+
+
+/*-----------------------------------------------------------------
+MPCF_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+
+#if (defined _CF_USE_DMA) && (defined NDS) && (defined ARM9)
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to read
+	MP_REG_SEC = numSecs;	
+	
+	// Set read sector
+	MP_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	MP_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	MP_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	MP_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to read
+	MP_REG_CMD = CF_CMD_READ;
+	
+	
+	while (j--)
+	{
+		// Wait until card is ready for reading
+		i = 0;
+		while (((MP_REG_STS & 0xff)!= CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Read data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)MP_DATA;
+		DMA3_DEST = (u32)buff;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
+ #else
+		DMA3COPY ( MP_DATA, buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *MP_DATA;
+				*buff_u8++ = temp & 0xFF;
+				*buff_u8++ = temp >> 8;
+			}
+		} else {
+		while(i--)
+			*buff++ = *MP_DATA; 
+		}
+#else
+		i=256;
+		while(i--)
+			*buff++ = *MP_DATA; 
+#endif
+	}
+#if (defined _CF_USE_DMA) && (defined NDS)
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+MPCF_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+	int i;
+	int j = (numSecs > 0 ? numSecs : 256);
+	u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+	u8 *buff_u8 = (u8*)buffer;
+	int temp;
+#endif
+	
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+	DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+	// Wait until CF card is finished previous commands
+	i=0;
+	while ((MP_REG_CMD & CF_STS_BUSY) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	
+	// Wait until card is ready for commands
+	i = 0;
+	while ((!(MP_REG_STS & CF_STS_INSERTED)) && (i < CARD_TIMEOUT))
+	{
+		i++;
+	}
+	if (i >= CARD_TIMEOUT)
+		return false;
+	
+	// Set number of sectors to write
+	MP_REG_SEC = numSecs;	
+	
+	// Set write sector
+	MP_REG_LBA1 = sector & 0xFF;						// 1st byte of sector number
+	MP_REG_LBA2 = (sector >> 8) & 0xFF;					// 2nd byte of sector number
+	MP_REG_LBA3 = (sector >> 16) & 0xFF;				// 3rd byte of sector number
+	MP_REG_LBA4 = ((sector >> 24) & 0x0F )| CF_CMD_LBA;	// last nibble of sector number
+	
+	// Set command to write
+	MP_REG_CMD = CF_CMD_WRITE;
+	
+	while (j--)
+	{
+		// Wait until card is ready for writing
+		i = 0;
+		while (((MP_REG_STS & 0xff) != CF_STS_READY) && (i < CARD_TIMEOUT))
+		{
+			i++;
+		}
+		if (i >= CARD_TIMEOUT)
+			return false;
+		
+		// Write data
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+		DMA3_SRC = (u32)buff;
+		DMA3_DEST = (u32)MP_DATA;
+		DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
+ #else
+		DMA3COPY( buff, MP_DATA, 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
+ #endif
+		buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+		i=256;
+		if ((u32)buff_u8 & 0x01) {
+			while(i--)
+			{
+				temp = *buff_u8++;
+				temp |= *buff_u8++ << 8;
+				*MP_DATA = temp;
+			}
+		} else {
+		while(i--)
+			*MP_DATA = *buff++; 
+		}
+#else
+		i=256;
+		while(i--)
+			*MP_DATA = *buff++; 
+#endif
+	}
+#if defined _CF_USE_DMA && defined NDS
+	// Wait for end of transfer before returning
+	while(DMA3_CR & DMA_BUSY);
+#endif
+	
+	return true;
+}
+
+/*-----------------------------------------------------------------
+MPCF_Shutdown
+unload the GBAMP CF interface
+-----------------------------------------------------------------*/
+bool MPCF_Shutdown(void) 
+{
+	return MPCF_ClearStatus() ;
+}
+
+/*-----------------------------------------------------------------
+MPCF_StartUp
+initializes the CF interface, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool MPCF_StartUp(void)
+{
+	u8 temp = MP_REG_LBA1;
+	MP_REG_LBA1 = (~temp & 0xFF);
+	temp = (~temp & 0xFF);
+	return (MP_REG_LBA1 == temp) ;
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_mpcf = {
+	DEVICE_TYPE_MPCF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&MPCF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&MPCF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&MPCF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&MPCF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&MPCF_Shutdown
+} ;
+
+/*-----------------------------------------------------------------
+MPCF_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE MPCF_GetInterface(void) {
+	return &io_mpcf ;
+} ;
+
+#endif // SUPPORT_MPCF


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,50 @@
+/*
+	io_mpcf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_MPCF_H
+#define IO_MPCF_H
+
+// 'MPCF'
+#define DEVICE_TYPE_MPCF 0x4643504D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE MPCF_GetInterface(void) ;
+
+#endif	// define IO_MPCF_H
+/*
+	io_mpcf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_MPCF_H
+#define IO_MPCF_H
+
+// 'MPCF'
+#define DEVICE_TYPE_MPCF 0x4643504D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE MPCF_GetInterface(void) ;
+
+#endif	// define IO_MPCF_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_mpcf.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,716 @@
+/*
+	io_nmmc.c
+
+	Hardware Routines for reading an SD or MMC card using
+	a Neoflash MK2 or MK3.
+
+	Written by www.neoflash.com
+
+	Submit bug reports for this device to the NeoFlash forums
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+	
+	2006-02-09 - www.neoflash.com:
+	 * First stable release
+	
+	2006-02-13 - Chishm
+	 * Added ReadMK2Config function
+	 * Added read config test to init function so no unnecessary card commands are sent
+	 * Changed data read and write functions to use multiple block commands
+*/
+
+#include "io_nmmc.h"
+
+#ifdef SUPPORT_NMMC
+
+#include <nds/card.h>
+
+int spi_freq = 3;
+
+#define MK2_CONFIG_ZIP_RAM_CLOSE		(1 << 5)
+#define MK2_CONFIG_GAME_FLASH_CLOSE		((1 << 4) | (1 << 0))
+//#define MK2_CONFIG_ZIP_RAM_CLOSE		((1 << 5) | (1 << 1))
+//#define MK2_CONFIG_GAME_FLASH_CLOSE		(1 << 4)
+
+#define MMC_READ_MULTIPLE_BLOCK		18
+#define MMC_READ_BLOCK		17
+#define MMC_WRITE_MULTIPLE_BLOCK	25
+#define MMC_WRITE_BLOCK		24
+#define MMC_STOP_TRANSMISSION	12
+#define MMC_SET_BLOCKLEN	16
+#define MMC_SET_BLOCK_COUNT	23
+#define MMC_SEND_CSD	9
+
+// SPI functions
+
+static inline void Neo_OpenSPI( u8 frequency )
+{
+	CARD_CR1 = 0x0000A040 | frequency;
+}
+
+static inline u8 Neo_SPI( u8 dataByte )
+{
+	CARD_EEPDATA = dataByte;
+	while (CARD_CR1 & 0x80);		// card busy
+	return CARD_EEPDATA;
+}
+
+static inline void Neo_CloseSPI ( void )
+{
+	CARD_CR1 = 0;
+}
+
+static inline void Neo_MK2GameMode()	{
+	Neo_OpenSPI(spi_freq);				// Enable DS Card's SPI port
+	Neo_SPI(0xF1);				// Switch to game mode
+	Neo_CloseSPI();				// Disable DS Card's SPI port
+}
+
+static inline void Neo_EnableEEPROM( bool enable )	{
+	Neo_OpenSPI(spi_freq);
+	if(enable)	Neo_SPI(0x06);
+	else 		Neo_SPI(0x0E);
+	Neo_CloseSPI();
+}
+
+void Neo_WriteMK2Config(u8 config) {
+	Neo_EnableEEPROM(true);
+	Neo_OpenSPI(spi_freq);
+	Neo_SPI(0xFA);					// Send mem conf write command
+	Neo_SPI(0x01);					// Send high byte (0x01)
+	Neo_SPI(config);				// Send low byte
+	Neo_CloseSPI();
+	Neo_EnableEEPROM(false);
+}
+
+u8 Neo_ReadMK2Config(void) 
+{
+	u8 config;
+	Neo_EnableEEPROM(true);
+	Neo_OpenSPI(spi_freq);
+	Neo_SPI(0xf8);					// Send mem conf read command
+	Neo_SPI(0x01);					// Send high byte
+	config = Neo_SPI(0x00);			// Get low byte
+	Neo_CloseSPI();
+	Neo_EnableEEPROM(false);
+	return config;
+}
+
+// Low level functions
+
+u8 selectMMC_command [8] = {0xFF, 0x00, 0x6A, 0xDF, 0x37, 0x59, 0x33, 0xA3};
+
+void Neo_SelectMMC (u8 dataByte) 
+{
+	selectMMC_command[1] = dataByte;	// Set enable / disable byte
+	cardWriteCommand (selectMMC_command);	// Send "5. Use the EEPROM CS to access the MK2 MMC/SD card"
+	CARD_CR2 = CARD_ACTIVATE | CARD_nRESET;
+	while (CARD_CR2 & CARD_BUSY);
+	return;
+}
+
+void Neo_EnableMMC( bool enable )
+{
+	if ( enable == false) {
+		Neo_CloseSPI ();
+		Neo_SelectMMC (0);
+		Neo_SelectMMC (0);
+	} else {
+		Neo_SelectMMC (1);
+		Neo_SelectMMC (1);
+		Neo_OpenSPI (spi_freq);
+	}
+	return;
+}
+
+void Neo_SendMMCCommand( u8 command, u32 argument )
+{
+	Neo_SPI (0xFF);
+	Neo_SPI (command | 0x40);
+	Neo_SPI ((argument >> 24) & 0xff);
+	Neo_SPI ((argument >> 16) & 0xff);
+	Neo_SPI ((argument >> 8) & 0xff) ;
+	Neo_SPI (argument & 0xff);
+	Neo_SPI (0x95);
+	Neo_SPI (0xFF);
+	return;
+}
+
+bool Neo_CheckMMCResponse( u8 response, u8 mask )	{
+	u32 i;
+	for(i=0;i<256;i++)	{
+		if( ( Neo_SPI( 0xFF ) & mask ) == response )
+			return true;
+	}
+	return false;
+}
+
+// Neo MMC functions
+
+bool Neo_InitMMC()	{
+	Neo_MK2GameMode();
+	Neo_WriteMK2Config( MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE);
+	
+	// Make sure the configuration was accepted
+	if (Neo_ReadMK2Config() != (MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE)) {
+		return false;	// If not, then it wasn't initialised properly
+	}
+	
+	return true;
+}
+
+// Neo MMC driver functions
+
+bool NMMC_IsInserted(void)	{
+	int i;
+	
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	Neo_SendMMCCommand(MMC_SEND_CSD, 0);
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+		Neo_EnableMMC( false );
+		return false;
+	}
+
+	// consume data from card, and send clocks.
+	for (i = 0; i < 28; i++) {
+		Neo_SPI(0xff);
+	}
+		
+	return true;
+}
+
+bool NMMC_ClearStatus (void) {
+	u32 i;
+	
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	for (i = 0; i < 10; i++) {
+		Neo_SPI(0xFF);			// Send 10 0xFF bytes to MMC card
+	}
+	Neo_SendMMCCommand(0, 0);	// Send GO_IDLE_STATE command
+	if( Neo_CheckMMCResponse( 0x01, 0xFF ) == false )	{		// Check that it replied with 0x01 (not idle, no other error)
+		Neo_EnableMMC( false );
+		return false;
+	}
+	for(i=0;i<256;i++)	{
+		Neo_SendMMCCommand(1, 0);	// Poll with SEND_OP_COND
+		if( Neo_CheckMMCResponse( 0x00, 0x01 ) == true ) {	// Check for idle state
+			Neo_EnableMMC( false );				// Close SPI port to MMC card
+			return true;						// Card is now idle
+		}
+	}
+	Neo_EnableMMC( false );
+	return false;
+}
+
+bool NMMC_Shutdown(void) {
+	return NMMC_ClearStatus();
+}
+
+bool NMMC_StartUp(void) {
+	int i;
+	int transSpeed;
+	if (Neo_InitMMC() == false) {
+		return false;
+	}
+	if (NMMC_ClearStatus() == false) {
+		return false;
+	}
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	
+	// Set block length
+	Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTE_PER_READ );
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	
+	// Check if we can use a higher SPI frequency
+	Neo_SendMMCCommand(MMC_SEND_CSD, 0);
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+		Neo_EnableMMC( false );
+		return false;
+	}
+	for (i = 0; i < 3; i++) {
+		Neo_SPI(0xFF);
+	}
+	transSpeed = Neo_SPI (0xFF);
+	for (i = 0; i < 24; i++) {
+		Neo_SPI(0xFF);
+	}
+	if ((transSpeed & 0xf0) >= 0x30) {
+		spi_freq = 0;
+	}
+	
+	Neo_EnableMMC( false );
+	return true;
+} 
+
+
+bool NMMC_WriteSectors (u32 sector, u8 numSecs, void* buffer)	
+{
+	u32 i;
+	u8 *p=buffer;
+	
+	int totalSecs = (numSecs == 0) ? 256 : numSecs;
+	sector *= BYTE_PER_READ;
+	
+	Neo_EnableMMC( true );												// Open SPI port to MMC card
+	Neo_SendMMCCommand( 25, sector );
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	
+	while (totalSecs--) {
+		Neo_SPI( 0xFC );												// Send Start Block token
+		for( i = 0; i < BYTE_PER_READ; i++ )							// Send a block of data
+			Neo_SPI( *p++ );
+		Neo_SPI( 0xFF );												// Send fake CRC16
+		Neo_SPI( 0xFF );												// Send fake CRC16
+		
+		if( ( Neo_SPI( 0xFF ) & 0x0F ) != 0x05 )	{					// Make sure the block was accepted
+			Neo_EnableMMC( false );
+			return false;
+		}
+		while( Neo_SPI( 0xFF ) == 0x00 );								// Wait for the block to be written
+	}
+	
+	// Stop transmission block
+	Neo_SPI( 0xFD );													// Send Stop Transmission Block token
+	for( i = 0; i < BYTE_PER_READ; i++ )								// Send a block of fake data
+		Neo_SPI( 0xFF );
+	Neo_SPI( 0xFF );													// Send fake CRC16
+	Neo_SPI( 0xFF );													// Send fake CRC16
+		
+	Neo_SPI (0xFF); 													// Send 8 clocks
+	while( Neo_SPI( 0xFF ) == 0x00 );									// Wait for the busy signal to clear
+
+	
+	for ( i = 0; i < 0x10; i++) {	
+		Neo_SPI (0xFF);													// Send clocks for the MMC card to finish what it's doing
+	}
+	
+	Neo_EnableMMC( false );											// Close SPI port to MMC card
+	return true;
+}
+
+bool NMMC_ReadSectors (u32 sector, u8 numSecs, void* buffer)	
+{
+	u32 i;
+	u8 *p=buffer;
+	
+	int totalSecs = (numSecs == 0) ? 256 : numSecs;
+	sector *= BYTE_PER_READ;
+	
+	Neo_EnableMMC( true );												// Open SPI port to MMC card
+	
+	while (totalSecs--) {
+		Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
+		if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{			// Make sure no errors occured
+			Neo_EnableMMC( false );
+			return false;
+		}
+	
+		if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+			Neo_EnableMMC( false );
+			return false;
+		}
+		for( i = 0; i < BYTE_PER_READ; i++ )							// Read in a block of data
+			*p++ = Neo_SPI( 0xFF );
+		Neo_SPI( 0xFF );												// Ignore CRC16
+		Neo_SPI( 0xFF );												// Ignore CRC16
+		sector += BYTE_PER_READ;
+	}
+	
+	Neo_EnableMMC( false );											// Close SPI port to MMC card
+	return true;
+}
+
+
+IO_INTERFACE io_nmmc = {
+	DEVICE_TYPE_NMMC,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&NMMC_StartUp,
+	(FN_MEDIUM_ISINSERTED)&NMMC_IsInserted,
+	(FN_MEDIUM_READSECTORS)&NMMC_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&NMMC_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&NMMC_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&NMMC_Shutdown
+} ;
+
+
+LPIO_INTERFACE NMMC_GetInterface(void) {
+	return &io_nmmc ;
+}
+
+#endif	// #ifdef SUPPORT_NMMC
+/*
+	io_nmmc.c
+
+	Hardware Routines for reading an SD or MMC card using
+	a Neoflash MK2 or MK3.
+
+	Written by www.neoflash.com
+
+	Submit bug reports for this device to the NeoFlash forums
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+	
+	2006-02-09 - www.neoflash.com:
+	 * First stable release
+	
+	2006-02-13 - Chishm
+	 * Added ReadMK2Config function
+	 * Added read config test to init function so no unnecessary card commands are sent
+	 * Changed data read and write functions to use multiple block commands
+*/
+
+#include "io_nmmc.h"
+
+#ifdef SUPPORT_NMMC
+
+#include <nds/card.h>
+
+int spi_freq = 3;
+
+#define MK2_CONFIG_ZIP_RAM_CLOSE		(1 << 5)
+#define MK2_CONFIG_GAME_FLASH_CLOSE		((1 << 4) | (1 << 0))
+//#define MK2_CONFIG_ZIP_RAM_CLOSE		((1 << 5) | (1 << 1))
+//#define MK2_CONFIG_GAME_FLASH_CLOSE		(1 << 4)
+
+#define MMC_READ_MULTIPLE_BLOCK		18
+#define MMC_READ_BLOCK		17
+#define MMC_WRITE_MULTIPLE_BLOCK	25
+#define MMC_WRITE_BLOCK		24
+#define MMC_STOP_TRANSMISSION	12
+#define MMC_SET_BLOCKLEN	16
+#define MMC_SET_BLOCK_COUNT	23
+#define MMC_SEND_CSD	9
+
+// SPI functions
+
+static inline void Neo_OpenSPI( u8 frequency )
+{
+	CARD_CR1 = 0x0000A040 | frequency;
+}
+
+static inline u8 Neo_SPI( u8 dataByte )
+{
+	CARD_EEPDATA = dataByte;
+	while (CARD_CR1 & 0x80);		// card busy
+	return CARD_EEPDATA;
+}
+
+static inline void Neo_CloseSPI ( void )
+{
+	CARD_CR1 = 0;
+}
+
+static inline void Neo_MK2GameMode()	{
+	Neo_OpenSPI(spi_freq);				// Enable DS Card's SPI port
+	Neo_SPI(0xF1);				// Switch to game mode
+	Neo_CloseSPI();				// Disable DS Card's SPI port
+}
+
+static inline void Neo_EnableEEPROM( bool enable )	{
+	Neo_OpenSPI(spi_freq);
+	if(enable)	Neo_SPI(0x06);
+	else 		Neo_SPI(0x0E);
+	Neo_CloseSPI();
+}
+
+void Neo_WriteMK2Config(u8 config) {
+	Neo_EnableEEPROM(true);
+	Neo_OpenSPI(spi_freq);
+	Neo_SPI(0xFA);					// Send mem conf write command
+	Neo_SPI(0x01);					// Send high byte (0x01)
+	Neo_SPI(config);				// Send low byte
+	Neo_CloseSPI();
+	Neo_EnableEEPROM(false);
+}
+
+u8 Neo_ReadMK2Config(void) 
+{
+	u8 config;
+	Neo_EnableEEPROM(true);
+	Neo_OpenSPI(spi_freq);
+	Neo_SPI(0xf8);					// Send mem conf read command
+	Neo_SPI(0x01);					// Send high byte
+	config = Neo_SPI(0x00);			// Get low byte
+	Neo_CloseSPI();
+	Neo_EnableEEPROM(false);
+	return config;
+}
+
+// Low level functions
+
+u8 selectMMC_command [8] = {0xFF, 0x00, 0x6A, 0xDF, 0x37, 0x59, 0x33, 0xA3};
+
+void Neo_SelectMMC (u8 dataByte) 
+{
+	selectMMC_command[1] = dataByte;	// Set enable / disable byte
+	cardWriteCommand (selectMMC_command);	// Send "5. Use the EEPROM CS to access the MK2 MMC/SD card"
+	CARD_CR2 = CARD_ACTIVATE | CARD_nRESET;
+	while (CARD_CR2 & CARD_BUSY);
+	return;
+}
+
+void Neo_EnableMMC( bool enable )
+{
+	if ( enable == false) {
+		Neo_CloseSPI ();
+		Neo_SelectMMC (0);
+		Neo_SelectMMC (0);
+	} else {
+		Neo_SelectMMC (1);
+		Neo_SelectMMC (1);
+		Neo_OpenSPI (spi_freq);
+	}
+	return;
+}
+
+void Neo_SendMMCCommand( u8 command, u32 argument )
+{
+	Neo_SPI (0xFF);
+	Neo_SPI (command | 0x40);
+	Neo_SPI ((argument >> 24) & 0xff);
+	Neo_SPI ((argument >> 16) & 0xff);
+	Neo_SPI ((argument >> 8) & 0xff) ;
+	Neo_SPI (argument & 0xff);
+	Neo_SPI (0x95);
+	Neo_SPI (0xFF);
+	return;
+}
+
+bool Neo_CheckMMCResponse( u8 response, u8 mask )	{
+	u32 i;
+	for(i=0;i<256;i++)	{
+		if( ( Neo_SPI( 0xFF ) & mask ) == response )
+			return true;
+	}
+	return false;
+}
+
+// Neo MMC functions
+
+bool Neo_InitMMC()	{
+	Neo_MK2GameMode();
+	Neo_WriteMK2Config( MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE);
+	
+	// Make sure the configuration was accepted
+	if (Neo_ReadMK2Config() != (MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE)) {
+		return false;	// If not, then it wasn't initialised properly
+	}
+	
+	return true;
+}
+
+// Neo MMC driver functions
+
+bool NMMC_IsInserted(void)	{
+	int i;
+	
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	Neo_SendMMCCommand(MMC_SEND_CSD, 0);
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+		Neo_EnableMMC( false );
+		return false;
+	}
+
+	// consume data from card, and send clocks.
+	for (i = 0; i < 28; i++) {
+		Neo_SPI(0xff);
+	}
+		
+	return true;
+}
+
+bool NMMC_ClearStatus (void) {
+	u32 i;
+	
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	for (i = 0; i < 10; i++) {
+		Neo_SPI(0xFF);			// Send 10 0xFF bytes to MMC card
+	}
+	Neo_SendMMCCommand(0, 0);	// Send GO_IDLE_STATE command
+	if( Neo_CheckMMCResponse( 0x01, 0xFF ) == false )	{		// Check that it replied with 0x01 (not idle, no other error)
+		Neo_EnableMMC( false );
+		return false;
+	}
+	for(i=0;i<256;i++)	{
+		Neo_SendMMCCommand(1, 0);	// Poll with SEND_OP_COND
+		if( Neo_CheckMMCResponse( 0x00, 0x01 ) == true ) {	// Check for idle state
+			Neo_EnableMMC( false );				// Close SPI port to MMC card
+			return true;						// Card is now idle
+		}
+	}
+	Neo_EnableMMC( false );
+	return false;
+}
+
+bool NMMC_Shutdown(void) {
+	return NMMC_ClearStatus();
+}
+
+bool NMMC_StartUp(void) {
+	int i;
+	int transSpeed;
+	if (Neo_InitMMC() == false) {
+		return false;
+	}
+	if (NMMC_ClearStatus() == false) {
+		return false;
+	}
+	Neo_EnableMMC( true );		// Open SPI port to MMC card
+	
+	// Set block length
+	Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTE_PER_READ );
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	
+	// Check if we can use a higher SPI frequency
+	Neo_SendMMCCommand(MMC_SEND_CSD, 0);
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+		Neo_EnableMMC( false );
+		return false;
+	}
+	for (i = 0; i < 3; i++) {
+		Neo_SPI(0xFF);
+	}
+	transSpeed = Neo_SPI (0xFF);
+	for (i = 0; i < 24; i++) {
+		Neo_SPI(0xFF);
+	}
+	if ((transSpeed & 0xf0) >= 0x30) {
+		spi_freq = 0;
+	}
+	
+	Neo_EnableMMC( false );
+	return true;
+} 
+
+
+bool NMMC_WriteSectors (u32 sector, u8 numSecs, void* buffer)	
+{
+	u32 i;
+	u8 *p=buffer;
+	
+	int totalSecs = (numSecs == 0) ? 256 : numSecs;
+	sector *= BYTE_PER_READ;
+	
+	Neo_EnableMMC( true );												// Open SPI port to MMC card
+	Neo_SendMMCCommand( 25, sector );
+	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured
+		Neo_EnableMMC( false );
+		return false;
+	}
+	
+	while (totalSecs--) {
+		Neo_SPI( 0xFC );												// Send Start Block token
+		for( i = 0; i < BYTE_PER_READ; i++ )							// Send a block of data
+			Neo_SPI( *p++ );
+		Neo_SPI( 0xFF );												// Send fake CRC16
+		Neo_SPI( 0xFF );												// Send fake CRC16
+		
+		if( ( Neo_SPI( 0xFF ) & 0x0F ) != 0x05 )	{					// Make sure the block was accepted
+			Neo_EnableMMC( false );
+			return false;
+		}
+		while( Neo_SPI( 0xFF ) == 0x00 );								// Wait for the block to be written
+	}
+	
+	// Stop transmission block
+	Neo_SPI( 0xFD );													// Send Stop Transmission Block token
+	for( i = 0; i < BYTE_PER_READ; i++ )								// Send a block of fake data
+		Neo_SPI( 0xFF );
+	Neo_SPI( 0xFF );													// Send fake CRC16
+	Neo_SPI( 0xFF );													// Send fake CRC16
+		
+	Neo_SPI (0xFF); 													// Send 8 clocks
+	while( Neo_SPI( 0xFF ) == 0x00 );									// Wait for the busy signal to clear
+
+	
+	for ( i = 0; i < 0x10; i++) {	
+		Neo_SPI (0xFF);													// Send clocks for the MMC card to finish what it's doing
+	}
+	
+	Neo_EnableMMC( false );											// Close SPI port to MMC card
+	return true;
+}
+
+bool NMMC_ReadSectors (u32 sector, u8 numSecs, void* buffer)	
+{
+	u32 i;
+	u8 *p=buffer;
+	
+	int totalSecs = (numSecs == 0) ? 256 : numSecs;
+	sector *= BYTE_PER_READ;
+	
+	Neo_EnableMMC( true );												// Open SPI port to MMC card
+	
+	while (totalSecs--) {
+		Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
+		if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{			// Make sure no errors occured
+			Neo_EnableMMC( false );
+			return false;
+		}
+	
+		if( Neo_CheckMMCResponse( 0xFE, 0xFF ) == false )	{			// Check for Start Block token
+			Neo_EnableMMC( false );
+			return false;
+		}
+		for( i = 0; i < BYTE_PER_READ; i++ )							// Read in a block of data
+			*p++ = Neo_SPI( 0xFF );
+		Neo_SPI( 0xFF );												// Ignore CRC16
+		Neo_SPI( 0xFF );												// Ignore CRC16
+		sector += BYTE_PER_READ;
+	}
+	
+	Neo_EnableMMC( false );											// Close SPI port to MMC card
+	return true;
+}
+
+
+IO_INTERFACE io_nmmc = {
+	DEVICE_TYPE_NMMC,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&NMMC_StartUp,
+	(FN_MEDIUM_ISINSERTED)&NMMC_IsInserted,
+	(FN_MEDIUM_READSECTORS)&NMMC_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&NMMC_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&NMMC_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&NMMC_Shutdown
+} ;
+
+
+LPIO_INTERFACE NMMC_GetInterface(void) {
+	return &io_nmmc ;
+}
+
+#endif	// #ifdef SUPPORT_NMMC


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,54 @@
+/*
+	io_NMMC.h 
+
+	Hardware Routines for reading an SD or MMC card using
+	a Neoflash MK2 or MK3.
+
+	Written by www.neoflash.com
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_NMMC_H
+#define IO_NMMC_H
+
+// 'NMMC'
+#define DEVICE_TYPE_NMMC 0x434D4D4E
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE NMMC_GetInterface(void) ;
+
+#endif	// define IO_NMMC_H
+/*
+	io_NMMC.h 
+
+	Hardware Routines for reading an SD or MMC card using
+	a Neoflash MK2 or MK3.
+
+	Written by www.neoflash.com
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_NMMC_H
+#define IO_NMMC_H
+
+// 'NMMC'
+#define DEVICE_TYPE_NMMC 0x434D4D4E
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE NMMC_GetInterface(void) ;
+
+#endif	// define IO_NMMC_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_nmmc.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,174 @@
+/*
+	io_sccf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the Super Card CF
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_sccf.h"
+
+#ifdef SUPPORT_SCCF
+
+#ifndef SUPPORT_MPCF
+ #error Supercard CF support requires GBAMP CF support
+#endif // SUPPORT_MPCF
+
+/*-----------------------------------------------------------------
+Since all CF addresses and commands are the same for the GBAMP,
+simply use it's functions instead.
+-----------------------------------------------------------------*/
+
+extern bool MPCF_IsInserted (void);
+extern bool MPCF_ClearStatus (void);
+extern bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer);
+extern bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer);
+
+
+/*-----------------------------------------------------------------
+SCCF_Unlock
+Returns true if SuperCard was unlocked, false if failed
+Added by MightyMax
+Modified by Chishm
+-----------------------------------------------------------------*/
+bool SCCF_Unlock(void)
+{
+#define CF_REG_LBA1 *(volatile unsigned short *)0x09060000
+	unsigned char temp;
+	volatile short *unlockAddress = (volatile short *)0x09FFFFFE;
+	*unlockAddress = 0xA55A ;
+	*unlockAddress = 0xA55A ;
+	*unlockAddress = 0x3 ;
+	*unlockAddress = 0x3 ;
+	// provoke a ready reply
+	temp = CF_REG_LBA1;
+	CF_REG_LBA1 = (~temp & 0xFF);
+	temp = (~temp & 0xFF);
+	return (CF_REG_LBA1 == temp);
+#undef CF_REG_LBA1
+} 
+
+bool SCCF_Shutdown(void) {
+	return MPCF_ClearStatus() ;
+} ;
+
+bool SCCF_StartUp(void) {
+	return SCCF_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_sccf = {
+	DEVICE_TYPE_SCCF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&SCCF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&MPCF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&MPCF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&MPCF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&SCCF_Shutdown
+} ;
+
+
+LPIO_INTERFACE SCCF_GetInterface(void) {
+	return &io_sccf ;
+} ;
+
+#endif // SUPPORT_SCCF
+/*
+	io_sccf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the Super Card CF
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_sccf.h"
+
+#ifdef SUPPORT_SCCF
+
+#ifndef SUPPORT_MPCF
+ #error Supercard CF support requires GBAMP CF support
+#endif // SUPPORT_MPCF
+
+/*-----------------------------------------------------------------
+Since all CF addresses and commands are the same for the GBAMP,
+simply use it's functions instead.
+-----------------------------------------------------------------*/
+
+extern bool MPCF_IsInserted (void);
+extern bool MPCF_ClearStatus (void);
+extern bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer);
+extern bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer);
+
+
+/*-----------------------------------------------------------------
+SCCF_Unlock
+Returns true if SuperCard was unlocked, false if failed
+Added by MightyMax
+Modified by Chishm
+-----------------------------------------------------------------*/
+bool SCCF_Unlock(void)
+{
+#define CF_REG_LBA1 *(volatile unsigned short *)0x09060000
+	unsigned char temp;
+	volatile short *unlockAddress = (volatile short *)0x09FFFFFE;
+	*unlockAddress = 0xA55A ;
+	*unlockAddress = 0xA55A ;
+	*unlockAddress = 0x3 ;
+	*unlockAddress = 0x3 ;
+	// provoke a ready reply
+	temp = CF_REG_LBA1;
+	CF_REG_LBA1 = (~temp & 0xFF);
+	temp = (~temp & 0xFF);
+	return (CF_REG_LBA1 == temp);
+#undef CF_REG_LBA1
+} 
+
+bool SCCF_Shutdown(void) {
+	return MPCF_ClearStatus() ;
+} ;
+
+bool SCCF_StartUp(void) {
+	return SCCF_Unlock() ;
+} ;
+
+
+IO_INTERFACE io_sccf = {
+	DEVICE_TYPE_SCCF,
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+	(FN_MEDIUM_STARTUP)&SCCF_StartUp,
+	(FN_MEDIUM_ISINSERTED)&MPCF_IsInserted,
+	(FN_MEDIUM_READSECTORS)&MPCF_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&MPCF_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&SCCF_Shutdown
+} ;
+
+
+LPIO_INTERFACE SCCF_GetInterface(void) {
+	return &io_sccf ;
+} ;
+
+#endif // SUPPORT_SCCF


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,50 @@
+/*
+	io_sccf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the Supercard CF
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_SCCF_H
+#define IO_SCCF_H
+
+// 'SCCF'
+#define DEVICE_TYPE_SCCF 0x46434353
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE SCCF_GetInterface(void) ;
+
+#endif	// define IO_SCCF_H
+/*
+	io_sccf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the Supercard CF
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_SCCF_H
+#define IO_SCCF_H
+
+// 'SCCF'
+#define DEVICE_TYPE_SCCF 0x46434353
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE SCCF_GetInterface(void) ;
+
+#endif	// define IO_SCCF_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_sccf.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,186 @@
+/*
+	io_scsd.c by SaTa.
+	based on io_sccf.c
+	
+	
+*/
+
+/*
+	io_sccf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the Super Card CF
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_scsd.h"
+
+/*-----------------------------------------------------------------
+Since all CF addresses and commands are the same for the GBAMP,
+simply use it's functions instead.
+-----------------------------------------------------------------*/
+
+extern bool MPCF_IsInserted (void);
+extern bool MPCF_ClearStatus (void);
+extern bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer);
+extern bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer);
+
+//	add by SaTa.
+extern void InitSCMode(void);	//	CF\x82Æ“\xAF\x82\xB6
+extern void ReadSector(u16 *buff,u32 sector,u8 ReadNumber);
+extern void WriteSector(u16 *buff,u32 sector,u8 writeNumber);
+extern bool MemoryCard_IsInserted(void);	//	CF\x82ƈႤ
+//	
+
+/*-----------------------------------------------------------------
+SCSD_Unlock
+Returns true if SuperCard was unlocked, false if failed
+Added by MightyMax
+Modified by Chishm
+-----------------------------------------------------------------*/
+bool SCSD_Unlock(void)
+{
+	InitSCMode();
+	return MemoryCard_IsInserted();
+} 
+
+bool SCSD_Shutdown(void) {
+	return MPCF_ClearStatus() ;
+} ;
+
+bool SCSD_StartUp(void) {
+	return SCSD_Unlock() ;
+} ;
+
+bool SCSD_ReadSectors (u32 sector, u8 ReadNumber, void* buff)
+{
+	ReadSector((u16 *)buff,sector,ReadNumber);
+	return true;
+}
+
+bool SCSD_WriteSectors (u32 sector, u8 writeNumber, void* buff)
+{
+	WriteSector((u16 *)buff,sector,writeNumber);
+	return true;
+}
+
+
+IO_INTERFACE io_scsd = {
+	0x44534353,	// 'SCSD'
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&SCSD_StartUp,
+	(FN_MEDIUM_ISINSERTED)&SCSD_Unlock,
+	(FN_MEDIUM_READSECTORS)&SCSD_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&SCSD_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&SCSD_Shutdown
+} ;
+
+
+LPIO_INTERFACE SCSD_GetInterface(void) {
+	return &io_scsd ;
+} ;
+/*
+	io_scsd.c by SaTa.
+	based on io_sccf.c
+	
+	
+*/
+
+/*
+	io_sccf.c based on
+
+	compact_flash.c
+	By chishm (Michael Chisholm)
+
+	Hardware Routines for reading a compact flash card
+	using the Super Card CF
+
+	CF routines modified with help from Darkfader
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_scsd.h"
+
+/*-----------------------------------------------------------------
+Since all CF addresses and commands are the same for the GBAMP,
+simply use it's functions instead.
+-----------------------------------------------------------------*/
+
+extern bool MPCF_IsInserted (void);
+extern bool MPCF_ClearStatus (void);
+extern bool MPCF_ReadSectors (u32 sector, u8 numSecs, void* buffer);
+extern bool MPCF_WriteSectors (u32 sector, u8 numSecs, void* buffer);
+
+//	add by SaTa.
+extern void InitSCMode(void);	//	CF\x82Æ“\xAF\x82\xB6
+extern void ReadSector(u16 *buff,u32 sector,u8 ReadNumber);
+extern void WriteSector(u16 *buff,u32 sector,u8 writeNumber);
+extern bool MemoryCard_IsInserted(void);	//	CF\x82ƈႤ
+//	
+
+/*-----------------------------------------------------------------
+SCSD_Unlock
+Returns true if SuperCard was unlocked, false if failed
+Added by MightyMax
+Modified by Chishm
+-----------------------------------------------------------------*/
+bool SCSD_Unlock(void)
+{
+	InitSCMode();
+	return MemoryCard_IsInserted();
+} 
+
+bool SCSD_Shutdown(void) {
+	return MPCF_ClearStatus() ;
+} ;
+
+bool SCSD_StartUp(void) {
+	return SCSD_Unlock() ;
+} ;
+
+bool SCSD_ReadSectors (u32 sector, u8 ReadNumber, void* buff)
+{
+	ReadSector((u16 *)buff,sector,ReadNumber);
+	return true;
+}
+
+bool SCSD_WriteSectors (u32 sector, u8 writeNumber, void* buff)
+{
+	WriteSector((u16 *)buff,sector,writeNumber);
+	return true;
+}
+
+
+IO_INTERFACE io_scsd = {
+	0x44534353,	// 'SCSD'
+	FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
+	(FN_MEDIUM_STARTUP)&SCSD_StartUp,
+	(FN_MEDIUM_ISINSERTED)&SCSD_Unlock,
+	(FN_MEDIUM_READSECTORS)&SCSD_ReadSectors,
+	(FN_MEDIUM_WRITESECTORS)&SCSD_WriteSectors,
+	(FN_MEDIUM_CLEARSTATUS)&MPCF_ClearStatus,
+	(FN_MEDIUM_SHUTDOWN)&SCSD_Shutdown
+} ;
+
+
+LPIO_INTERFACE SCSD_GetInterface(void) {
+	return &io_scsd ;
+} ;


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,58 @@
+/*
+	io_scsd.h by SaTa.
+	based on io_sccf.h
+	
+	
+*/
+
+/*
+	io_sccf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_SCSD_H
+#define IO_SCSD_H
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE SCSD_GetInterface(void) ;
+
+#endif	// define IO_SCSD_H
+/*
+	io_scsd.h by SaTa.
+	based on io_sccf.h
+	
+	
+*/
+
+/*
+	io_sccf.h 
+
+	Hardware Routines for reading a compact flash card
+	using the GBA Movie Player
+
+	This software is completely free. No warranty is provided.
+	If you use it, please give me credit and email me about your
+	project at chishm at hotmail.com
+
+	See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_SCSD_H
+#define IO_SCSD_H
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE SCSD_GetInterface(void) ;
+
+#endif	// define IO_SCSD_H


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd_asm.s
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd_asm.s	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/fat/io_scsd_asm.s	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,1042 @@
+    .TEXT
+ at --------------------------------sd data--------------------------------
+.equ sd_comadd,0x9800000
+.equ sd_dataadd,0x9000000  
+.equ sd_dataradd,0x9100000
+ at -----------------viod sd_data_write_s(u16 *buff,u16* crc16buff)-------------------
+    .ALIGN
+    .GLOBAL sd_data_write_s	
+    .CODE 32
+sd_data_write_s:
+	stmfd   r13!,{r4-r5}
+	mov	r5,#512
+	mov	r2,#sd_dataadd
+sd_data_write_busy:
+	ldrh	r3,[r2]   
+	tst	r3,#0x100
+	beq	sd_data_write_busy
+
+	ldrh	r3,[r2]   
+
+	mov	r3,#0 @star bit
+	strh	r3,[r2]
+sd_data_write_loop:
+	ldrh	r3,[r0],#2
+	add	r3,r3,r3,lsl #20
+	mov	r4,r3,lsl #8
+	stmia   r2,{r3-r4}  
+ 
+        subs    r5, r5, #2                 
+        bne     sd_data_write_loop  
+
+	cmp	r1,#0
+	movne	r0,r1
+	movne	r1,#0
+	movne	r5,#8
+	bne	sd_data_write_loop
+
+	mov	r3,#0xff @end bit
+	strh	r3,[r2]
+sd_data_write_loop2:
+	ldrh	r3,[r2]   
+	tst	r3,#0x100
+	bne	sd_data_write_loop2
+
+	ldmia   r2,{r3-r4} 
+
+	ldmfd	r13!,{r4-r5}
+	bx      r14
+ at -----------------end sd_data_write_s-------------------
+
+ at ----------void sd_data_read_s(u16 *buff)-------------
+    .ALIGN
+    .GLOBAL sd_data_read_s	
+    .CODE 32
+sd_data_read_s:
+	stmfd   r13!,{r4}
+	mov	r1,#sd_dataradd
+sd_data_read_loop1:
+	ldrh	r3,[r1]   @star bit
+	tst	r3,#0x100
+	bne	sd_data_read_loop1
+	mov	r2,#512
+sd_data_read_loop:
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+        subs    r2, r2, #16                
+        bne     sd_data_read_loop 
+
+	ldmia	r1,{r3-r4} @crc 16
+	ldmia	r1,{r3-r4}  
+	ldmia	r1,{r3-r4}  
+	ldmia	r1,{r3-r4}  
+	ldrh	r3,[r1]    @end bit
+	ldmfd	r13!,{r4}  
+	bx      r14
+ at ----------end sd_data_read_s-------------
+
+ at ------void sd_com_crc16_s(u16* buff,u16 num,u16* crc16buff)
+    .ALIGN
+    .GLOBAL	sd_crc16_s 
+    .CODE 32
+sd_crc16_s:
+	stmfd   r13!,{r4-r9}
+	mov	r9,r2
+
+	mov	r3,#0  
+	mov	r4,#0  
+	mov	r5,#0  
+	mov	r6,#0  
+
+	ldr	r7,=0x80808080
+	ldr	r8,=0x1021
+	mov	r1,r1,lsl #3
+sd_crc16_loop:
+
+	tst	r7,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	r3,r3,lsl #1
+	tst	r3,#0x10000
+	eorne	r3,r3,r8
+	tst	r2,r7,lsr #24
+	eorne	r3,r3,r8
+	
+	mov	r4,r4,lsl #1
+	tst	r4,#0x10000
+	eorne	r4,r4,r8
+	tst	r2,r7,lsr #25
+	eorne	r4,r4,r8
+	
+	mov	r5,r5,lsl #1
+	tst	r5,#0x10000
+	eorne	r5,r5,r8
+	tst	r2,r7,lsr #26
+	eorne	r5,r5,r8
+	
+	mov	r6,r6,lsl #1
+	tst	r6,#0x10000
+	eorne	r6,r6,r8
+	tst	r2,r7,lsr #27
+	eorne	r6,r6,r8
+
+	mov	r7,r7,ror #4
+	subs	r1,r1,#4
+        bne     sd_crc16_loop 
+
+	mov	r2,r9
+	mov	r8,#16
+sd_crc16_write_data:
+	mov	r7,r7,lsl #4
+	tst	r3,#0x8000
+	orrne	r7,r7,#8
+	tst	r4,#0x8000
+	orrne	r7,r7,#4
+	tst	r5,#0x8000
+	orrne	r7,r7,#2
+	tst	r6,#0x8000
+	orrne	r7,r7,#1
+
+	mov	r3,r3,lsl #1
+	mov	r4,r4,lsl #1
+	mov	r5,r5,lsl #1
+	mov	r6,r6,lsl #1
+
+	sub	r8,r8,#1
+	tst	r8,#1
+	streqb	r7,[r2],#1
+	cmp	r8,#0
+	bne	sd_crc16_write_data
+
+	ldmfd	r13!,{r4-r9}
+	bx      r14
+ at ------end sd_com_crc16_s-----------------------------------
+
+ at --------------u8 sd_crc7_s(u16* buff,u16 num)----------------------------
+    .ALIGN
+    .GLOBAL	sd_crc7_s 
+    .CODE 32
+sd_crc7_s:
+	stmfd   r13!,{r4}
+
+	mov	r3,#0
+	ldr	r4,=0x80808080
+	mov	r1,r1,lsl #3 @ *8
+sd_crc7_loop:
+	tst	r4,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	r3,r3,lsl #1
+
+	tst	r3,#0x80
+	eorne	r3,r3,#0x9
+
+	tst	r2,r4,lsr #24
+	eorne	r3,r3,#0x9
+
+	mov	r4,r4,ror #1
+	subs	r1,r1,#1
+        bne     sd_crc7_loop 
+
+	mov	r3,r3,lsl #1
+	add	r0,r3,#1
+	ldmfd	r13!,{r4}
+	bx      r14
+ at --------------end sd_crc7_s----------------------------
+
+ at --------------sd_com_read_s(u16* buff,u32 num)------------------
+		.ALIGN
+		.GLOBAL	 sd_com_read_s 
+		.CODE 32
+
+sd_com_read_s:
+	stmfd   r13!,{r4-r6}
+	mov	r2,#sd_comadd
+sd_com_read_loop1:
+	ldrh	r3,[r2] @star bit
+	tst	r3,#1
+	bne	sd_com_read_loop1
+
+sd_com_read_loop:
+	ldmia   r2,{r3-r6}
+        subs    r1, r1, #1                  
+        bne     sd_com_read_loop  
+	ldmfd	r13!,{r4-r6}
+	bx      r14
+ at --------------end sd_com_read_s------------------
+
+ at -------------------void sd_com_write_s(u16* buff,u32 num)-----------------
+
+		.ALIGN
+		.GLOBAL	 sd_com_write_s
+		.CODE 32
+sd_com_write_s:
+	stmfd   r13!,{r4-r6}
+	
+	mov	r2,#sd_comadd
+sd_com_write_busy:
+	ldrh	r3,[r2]   
+	tst	r3,#0x1
+	beq	sd_com_write_busy
+
+	ldrh	r3,[r2]  
+
+sd_com_write_loop:
+        ldrb   r3,[r0],#1
+	add	r3,r3,r3,lsl #17
+	mov	r4,r3,lsl #2
+	mov	r5,r4,lsl #2
+	mov	r6,r5,lsl #2
+        stmia   r2,{r3-r6}  
+        subs    r1, r1, #1                  
+        bne     sd_com_write_loop  
+	ldmfd   r13!,{r4-r6}
+
+	bx      r14
+ at -------------------end sd_com_write_s-----------------
+
+ at -----------------void send_clk(u32 num)---------
+		.ALIGN
+		.GLOBAL	 send_clk 
+		.CODE 32
+
+send_clk:
+	mov	r1,#sd_comadd
+send_clk_loop1:
+	ldrh	r3,[r1]
+	subs	r0,r0,#1
+	bne	send_clk_loop1
+	bx	r14
+ at -----------------end send_clk---------
+
+ at ---------------------------void SDCommand(u8 command,u8 num,u32 sector)--------------------
+		.ALIGN
+		.GLOBAL	 SDCommand 
+		.CODE 32
+ at void SDCommand(u8 command,u8 num,u32 sector )
+@{
+@	u8 databuff[6];
+@	register u8 *char1;
+@	register u8 *char2;
+@
+@	char1=(u8*)(((u32)&sector)+3);
+@	char2=(u8*)databuff;
+@	*char2++=coma+0x40;
+@	*char2++=*char1--;
+@	*char2++=*char1--;
+@	*char2++=*char1--;
+@	*char2++=*char1;
+@	*char2=sd_crc7_s((u32)databuff,5);
+@
+@	sd_com_write_s((u32)databuff,6);
+@
+@}
+SDCommand:
+	stmfd   r13!,{r14}
+
+	sub	r13,r13,#16
+	add	r0,r0,#0x40
+	strb	r0,[r13,#4]
+
+	mov	r1,r2,lsr #24
+	strb	r1,[r13,#5]
+	mov	r1,r2,lsr #16
+	strb	r1,[r13,#6]
+	mov	r1,r2,lsr #8
+	strb	r1,[r13,#7]
+	strb	r2,[r13,#8]
+	add	r0,r13,#4
+	mov	r1,#5
+	bl	sd_crc7_s
+	strb	r0,[r13,#9]
+	add	r0,r13,#4
+	mov	r1,#6
+	bl	sd_com_write_s
+
+	add	r13,r13,#16
+	ldmfd   r13!,{r15}
+@	bx	r14
+ at ---------------------------end SDCommand--------------------
+
+ at ----------void ReadSector(u16 *buff,u32 sector,u8 readnum)-------------
+		.ALIGN
+		.GLOBAL	 ReadSector @ r0:Srcp r1:num ok
+		.CODE 32
+
+ at void ReadSector(u16 *buff,u32 sector,u8 readnum)
+@{
+@	register u16 i,j;
+@	i=readnum;
+@	sectno<<=9;
+@	SDCommand(18,0,sector); 
+@	for (j=0;j<i ; j++)
+@	{
+@		sd_data_read_s((u32)buff+j*512);
+@	}
+@	SDCommand(12,0,0); 
+@	get_resp();
+@	send_clk(0x10);
+@
+@}
+ReadSector:
+	stmfd   r13!,{r4-r6,r14}
+
+	mov	r4,r0
+	mov	r5,r2
+
+	mov	r2,r1,lsl #9
+	mov	r0,#18
+	mov	r1,#0
+	bl	SDCommand
+	mov	r6,#0
+beginforj_ReadSector:
+	cmp	r6,r5
+	bge	endforj_ReadSector
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9 
+	bl	sd_data_read_s
+	add	r6,r6,#1
+	b	beginforj_ReadSector
+endforj_ReadSector:
+	mov	r0,#12
+	mov	r1,#0
+	mov	r2,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	mov	r0,#1
+	ldmfd   r13!,{r4-r6,r15}
+@	bx	r14
+ at ----------end ReadSector------------
+
+ at -----------void get_resp(void)-------------------
+
+
+		.ALIGN
+		.GLOBAL	 get_resp @ r0:Srcp r1:num ok
+		.CODE 32
+get_resp:
+
+	stmfd   r13!,{r14}
+	mov	r1,#6
+	bl	sd_com_read_s
+	ldmfd   r13!,{r15}
+ at -----------end get_resp-------------------
+
+
+ at ---------------void WriteSector(u16 *buff,u32 sector,u8 writenum)---------------------
+		.ALIGN
+		.GLOBAL	 WriteSector @ r0:Srcp r1:num ok
+		.CODE 32
+
+ at void WriteSector(u16 *buff,u32 sector,u8 writenum)
+@{
+@	register u16 i,j;
+@	u16 crc16[5];
+@	i=writenum;
+@
+@	sectno<<=9;
+@
+@	SDCommand(25,0,sector); 
+@	get_resp();
+@	send_clk(0x10); 
+@
+@	for (j=0;j<i ; j++)
+@	{
+@		sd_crc16_s((u32)(u32)buff+j*512,512,(u32)crc16);
+@		sd_data_write_s((u32)buff+j*512,(u32)crc16);
+@		send_clk(0x10); 
+@	}
+@	SDCommand(12,0,0); 
+@	get_resp();
+@	send_clk(0x10);
+@	while((*(u16*)sd_dataadd &0x0100)==0);
+@
+@}
+@
+WriteSector:
+	stmfd   r13!,{r4-r6,r14}
+
+	sub	r13,r13,#20
+
+	mov	r4,r0
+	mov	r5,r2
+
+	mov	r2,r1,lsl #9
+	mov	r0,#25
+	mov	r1,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	mov	r6,#0
+
+beginforj_WriteSector:
+	cmp	r6,r5
+	bge	endforj_WriteSector
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9
+	mov	r1,#512
+	add	r2,r13,#4
+	bl	sd_crc16_s
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9 
+	add	r1,r13,#4
+	bl	sd_data_write_s
+	mov	r0,#0x10
+	bl	send_clk
+	add	r6,r6,#1
+	b	beginforj_WriteSector
+endforj_WriteSector:
+	mov	r0,#12
+	mov	r1,#0
+	mov	r2,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	ldr	r0,=sd_dataadd
+beginwhile_WriteSector:
+	ldrh	r1,[r0]
+	tst	r1,#0x0100
+	beq	beginwhile_WriteSector
+	mov	r0,#1
+	add	r13,r13,#20
+	ldmfd   r13!,{r4-r6,r15}
+ at ---------------end WriteSector--------------------
+
+ at ----------------void InitSCMode(void)---------------
+		.ALIGN
+		.GLOBAL	 InitSCMode
+		.CODE 32
+InitSCMode:
+	mvn     r0,#0x0F6000000 
+	sub     r0,r0,#0x01
+	mov     r1,#0x0A500
+	add     r1,r1,#0x5A
+	strh    r1,[r0]
+	strh    r1,[r0]
+	mov	r2,#3
+	strh    r2,[r0]
+	strh    r2,[r0]
+	bx	r14
+ at ----------------end InitSCMode ---------------
+
+ at ----------------bool MemoryCard_IsInserted(void)---------------
+		.ALIGN
+		.GLOBAL	 MemoryCard_IsInserted
+		.CODE 32
+
+MemoryCard_IsInserted:
+	ldr	r0,=sd_comadd
+	ldrh	r1,[r0]
+	tst	r1,#0x300
+	moveq	r0,#1
+	movne	r0,#0
+	bx	r14
+ at ----------------end MemoryCard_IsInserted---------------
+
+    .END
+
+
+
+
+
+
+
+
+
+
+
+    .TEXT
+ at --------------------------------sd data--------------------------------
+.equ sd_comadd,0x9800000
+.equ sd_dataadd,0x9000000  
+.equ sd_dataradd,0x9100000
+ at -----------------viod sd_data_write_s(u16 *buff,u16* crc16buff)-------------------
+    .ALIGN
+    .GLOBAL sd_data_write_s	
+    .CODE 32
+sd_data_write_s:
+	stmfd   r13!,{r4-r5}
+	mov	r5,#512
+	mov	r2,#sd_dataadd
+sd_data_write_busy:
+	ldrh	r3,[r2]   
+	tst	r3,#0x100
+	beq	sd_data_write_busy
+
+	ldrh	r3,[r2]   
+
+	mov	r3,#0 @star bit
+	strh	r3,[r2]
+sd_data_write_loop:
+	ldrh	r3,[r0],#2
+	add	r3,r3,r3,lsl #20
+	mov	r4,r3,lsl #8
+	stmia   r2,{r3-r4}  
+ 
+        subs    r5, r5, #2                 
+        bne     sd_data_write_loop  
+
+	cmp	r1,#0
+	movne	r0,r1
+	movne	r1,#0
+	movne	r5,#8
+	bne	sd_data_write_loop
+
+	mov	r3,#0xff @end bit
+	strh	r3,[r2]
+sd_data_write_loop2:
+	ldrh	r3,[r2]   
+	tst	r3,#0x100
+	bne	sd_data_write_loop2
+
+	ldmia   r2,{r3-r4} 
+
+	ldmfd	r13!,{r4-r5}
+	bx      r14
+ at -----------------end sd_data_write_s-------------------
+
+ at ----------void sd_data_read_s(u16 *buff)-------------
+    .ALIGN
+    .GLOBAL sd_data_read_s	
+    .CODE 32
+sd_data_read_s:
+	stmfd   r13!,{r4}
+	mov	r1,#sd_dataradd
+sd_data_read_loop1:
+	ldrh	r3,[r1]   @star bit
+	tst	r3,#0x100
+	bne	sd_data_read_loop1
+	mov	r2,#512
+sd_data_read_loop:
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+	ldmia	r1,{r3-r4} 
+	mov	r3,r4,lsr #16
+	strh	r3 ,[r0],#2
+
+        subs    r2, r2, #16                
+        bne     sd_data_read_loop 
+
+	ldmia	r1,{r3-r4} @crc 16
+	ldmia	r1,{r3-r4}  
+	ldmia	r1,{r3-r4}  
+	ldmia	r1,{r3-r4}  
+	ldrh	r3,[r1]    @end bit
+	ldmfd	r13!,{r4}  
+	bx      r14
+ at ----------end sd_data_read_s-------------
+
+ at ------void sd_com_crc16_s(u16* buff,u16 num,u16* crc16buff)
+    .ALIGN
+    .GLOBAL	sd_crc16_s 
+    .CODE 32
+sd_crc16_s:
+	stmfd   r13!,{r4-r9}
+	mov	r9,r2
+
+	mov	r3,#0  
+	mov	r4,#0  
+	mov	r5,#0  
+	mov	r6,#0  
+
+	ldr	r7,=0x80808080
+	ldr	r8,=0x1021
+	mov	r1,r1,lsl #3
+sd_crc16_loop:
+
+	tst	r7,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	r3,r3,lsl #1
+	tst	r3,#0x10000
+	eorne	r3,r3,r8
+	tst	r2,r7,lsr #24
+	eorne	r3,r3,r8
+	
+	mov	r4,r4,lsl #1
+	tst	r4,#0x10000
+	eorne	r4,r4,r8
+	tst	r2,r7,lsr #25
+	eorne	r4,r4,r8
+	
+	mov	r5,r5,lsl #1
+	tst	r5,#0x10000
+	eorne	r5,r5,r8
+	tst	r2,r7,lsr #26
+	eorne	r5,r5,r8
+	
+	mov	r6,r6,lsl #1
+	tst	r6,#0x10000
+	eorne	r6,r6,r8
+	tst	r2,r7,lsr #27
+	eorne	r6,r6,r8
+
+	mov	r7,r7,ror #4
+	subs	r1,r1,#4
+        bne     sd_crc16_loop 
+
+	mov	r2,r9
+	mov	r8,#16
+sd_crc16_write_data:
+	mov	r7,r7,lsl #4
+	tst	r3,#0x8000
+	orrne	r7,r7,#8
+	tst	r4,#0x8000
+	orrne	r7,r7,#4
+	tst	r5,#0x8000
+	orrne	r7,r7,#2
+	tst	r6,#0x8000
+	orrne	r7,r7,#1
+
+	mov	r3,r3,lsl #1
+	mov	r4,r4,lsl #1
+	mov	r5,r5,lsl #1
+	mov	r6,r6,lsl #1
+
+	sub	r8,r8,#1
+	tst	r8,#1
+	streqb	r7,[r2],#1
+	cmp	r8,#0
+	bne	sd_crc16_write_data
+
+	ldmfd	r13!,{r4-r9}
+	bx      r14
+ at ------end sd_com_crc16_s-----------------------------------
+
+ at --------------u8 sd_crc7_s(u16* buff,u16 num)----------------------------
+    .ALIGN
+    .GLOBAL	sd_crc7_s 
+    .CODE 32
+sd_crc7_s:
+	stmfd   r13!,{r4}
+
+	mov	r3,#0
+	ldr	r4,=0x80808080
+	mov	r1,r1,lsl #3 @ *8
+sd_crc7_loop:
+	tst	r4,#0x80
+	ldrneb	r2,[r0],#1
+
+	mov	r3,r3,lsl #1
+
+	tst	r3,#0x80
+	eorne	r3,r3,#0x9
+
+	tst	r2,r4,lsr #24
+	eorne	r3,r3,#0x9
+
+	mov	r4,r4,ror #1
+	subs	r1,r1,#1
+        bne     sd_crc7_loop 
+
+	mov	r3,r3,lsl #1
+	add	r0,r3,#1
+	ldmfd	r13!,{r4}
+	bx      r14
+ at --------------end sd_crc7_s----------------------------
+
+ at --------------sd_com_read_s(u16* buff,u32 num)------------------
+		.ALIGN
+		.GLOBAL	 sd_com_read_s 
+		.CODE 32
+
+sd_com_read_s:
+	stmfd   r13!,{r4-r6}
+	mov	r2,#sd_comadd
+sd_com_read_loop1:
+	ldrh	r3,[r2] @star bit
+	tst	r3,#1
+	bne	sd_com_read_loop1
+
+sd_com_read_loop:
+	ldmia   r2,{r3-r6}
+        subs    r1, r1, #1                  
+        bne     sd_com_read_loop  
+	ldmfd	r13!,{r4-r6}
+	bx      r14
+ at --------------end sd_com_read_s------------------
+
+ at -------------------void sd_com_write_s(u16* buff,u32 num)-----------------
+
+		.ALIGN
+		.GLOBAL	 sd_com_write_s
+		.CODE 32
+sd_com_write_s:
+	stmfd   r13!,{r4-r6}
+	
+	mov	r2,#sd_comadd
+sd_com_write_busy:
+	ldrh	r3,[r2]   
+	tst	r3,#0x1
+	beq	sd_com_write_busy
+
+	ldrh	r3,[r2]  
+
+sd_com_write_loop:
+        ldrb   r3,[r0],#1
+	add	r3,r3,r3,lsl #17
+	mov	r4,r3,lsl #2
+	mov	r5,r4,lsl #2
+	mov	r6,r5,lsl #2
+        stmia   r2,{r3-r6}  
+        subs    r1, r1, #1                  
+        bne     sd_com_write_loop  
+	ldmfd   r13!,{r4-r6}
+
+	bx      r14
+ at -------------------end sd_com_write_s-----------------
+
+ at -----------------void send_clk(u32 num)---------
+		.ALIGN
+		.GLOBAL	 send_clk 
+		.CODE 32
+
+send_clk:
+	mov	r1,#sd_comadd
+send_clk_loop1:
+	ldrh	r3,[r1]
+	subs	r0,r0,#1
+	bne	send_clk_loop1
+	bx	r14
+ at -----------------end send_clk---------
+
+ at ---------------------------void SDCommand(u8 command,u8 num,u32 sector)--------------------
+		.ALIGN
+		.GLOBAL	 SDCommand 
+		.CODE 32
+ at void SDCommand(u8 command,u8 num,u32 sector )
+@{
+@	u8 databuff[6];
+@	register u8 *char1;
+@	register u8 *char2;
+@
+@	char1=(u8*)(((u32)&sector)+3);
+@	char2=(u8*)databuff;
+@	*char2++=coma+0x40;
+@	*char2++=*char1--;
+@	*char2++=*char1--;
+@	*char2++=*char1--;
+@	*char2++=*char1;
+@	*char2=sd_crc7_s((u32)databuff,5);
+@
+@	sd_com_write_s((u32)databuff,6);
+@
+@}
+SDCommand:
+	stmfd   r13!,{r14}
+
+	sub	r13,r13,#16
+	add	r0,r0,#0x40
+	strb	r0,[r13,#4]
+
+	mov	r1,r2,lsr #24
+	strb	r1,[r13,#5]
+	mov	r1,r2,lsr #16
+	strb	r1,[r13,#6]
+	mov	r1,r2,lsr #8
+	strb	r1,[r13,#7]
+	strb	r2,[r13,#8]
+	add	r0,r13,#4
+	mov	r1,#5
+	bl	sd_crc7_s
+	strb	r0,[r13,#9]
+	add	r0,r13,#4
+	mov	r1,#6
+	bl	sd_com_write_s
+
+	add	r13,r13,#16
+	ldmfd   r13!,{r15}
+@	bx	r14
+ at ---------------------------end SDCommand--------------------
+
+ at ----------void ReadSector(u16 *buff,u32 sector,u8 readnum)-------------
+		.ALIGN
+		.GLOBAL	 ReadSector @ r0:Srcp r1:num ok
+		.CODE 32
+
+ at void ReadSector(u16 *buff,u32 sector,u8 readnum)
+@{
+@	register u16 i,j;
+@	i=readnum;
+@	sectno<<=9;
+@	SDCommand(18,0,sector); 
+@	for (j=0;j<i ; j++)
+@	{
+@		sd_data_read_s((u32)buff+j*512);
+@	}
+@	SDCommand(12,0,0); 
+@	get_resp();
+@	send_clk(0x10);
+@
+@}
+ReadSector:
+	stmfd   r13!,{r4-r6,r14}
+
+	mov	r4,r0
+	mov	r5,r2
+
+	mov	r2,r1,lsl #9
+	mov	r0,#18
+	mov	r1,#0
+	bl	SDCommand
+	mov	r6,#0
+beginforj_ReadSector:
+	cmp	r6,r5
+	bge	endforj_ReadSector
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9 
+	bl	sd_data_read_s
+	add	r6,r6,#1
+	b	beginforj_ReadSector
+endforj_ReadSector:
+	mov	r0,#12
+	mov	r1,#0
+	mov	r2,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	mov	r0,#1
+	ldmfd   r13!,{r4-r6,r15}
+@	bx	r14
+ at ----------end ReadSector------------
+
+ at -----------void get_resp(void)-------------------
+
+
+		.ALIGN
+		.GLOBAL	 get_resp @ r0:Srcp r1:num ok
+		.CODE 32
+get_resp:
+
+	stmfd   r13!,{r14}
+	mov	r1,#6
+	bl	sd_com_read_s
+	ldmfd   r13!,{r15}
+ at -----------end get_resp-------------------
+
+
+ at ---------------void WriteSector(u16 *buff,u32 sector,u8 writenum)---------------------
+		.ALIGN
+		.GLOBAL	 WriteSector @ r0:Srcp r1:num ok
+		.CODE 32
+
+ at void WriteSector(u16 *buff,u32 sector,u8 writenum)
+@{
+@	register u16 i,j;
+@	u16 crc16[5];
+@	i=writenum;
+@
+@	sectno<<=9;
+@
+@	SDCommand(25,0,sector); 
+@	get_resp();
+@	send_clk(0x10); 
+@
+@	for (j=0;j<i ; j++)
+@	{
+@		sd_crc16_s((u32)(u32)buff+j*512,512,(u32)crc16);
+@		sd_data_write_s((u32)buff+j*512,(u32)crc16);
+@		send_clk(0x10); 
+@	}
+@	SDCommand(12,0,0); 
+@	get_resp();
+@	send_clk(0x10);
+@	while((*(u16*)sd_dataadd &0x0100)==0);
+@
+@}
+@
+WriteSector:
+	stmfd   r13!,{r4-r6,r14}
+
+	sub	r13,r13,#20
+
+	mov	r4,r0
+	mov	r5,r2
+
+	mov	r2,r1,lsl #9
+	mov	r0,#25
+	mov	r1,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	mov	r6,#0
+
+beginforj_WriteSector:
+	cmp	r6,r5
+	bge	endforj_WriteSector
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9
+	mov	r1,#512
+	add	r2,r13,#4
+	bl	sd_crc16_s
+	mov	r0,r4
+	add	r0,r0,r6,lsl #9 
+	add	r1,r13,#4
+	bl	sd_data_write_s
+	mov	r0,#0x10
+	bl	send_clk
+	add	r6,r6,#1
+	b	beginforj_WriteSector
+endforj_WriteSector:
+	mov	r0,#12
+	mov	r1,#0
+	mov	r2,#0
+	bl	SDCommand
+	bl	get_resp
+	mov	r0,#0x10
+	bl	send_clk
+	ldr	r0,=sd_dataadd
+beginwhile_WriteSector:
+	ldrh	r1,[r0]
+	tst	r1,#0x0100
+	beq	beginwhile_WriteSector
+	mov	r0,#1
+	add	r13,r13,#20
+	ldmfd   r13!,{r4-r6,r15}
+ at ---------------end WriteSector--------------------
+
+ at ----------------void InitSCMode(void)---------------
+		.ALIGN
+		.GLOBAL	 InitSCMode
+		.CODE 32
+InitSCMode:
+	mvn     r0,#0x0F6000000 
+	sub     r0,r0,#0x01
+	mov     r1,#0x0A500
+	add     r1,r1,#0x5A
+	strh    r1,[r0]
+	strh    r1,[r0]
+	mov	r2,#3
+	strh    r2,[r0]
+	strh    r2,[r0]
+	bx	r14
+ at ----------------end InitSCMode ---------------
+
+ at ----------------bool MemoryCard_IsInserted(void)---------------
+		.ALIGN
+		.GLOBAL	 MemoryCard_IsInserted
+		.CODE 32
+
+MemoryCard_IsInserted:
+	ldr	r0,=sd_comadd
+	ldrh	r1,[r0]
+	tst	r1,#0x300
+	moveq	r0,#1
+	movne	r0,#0
+	bx	r14
+ at ----------------end MemoryCard_IsInserted---------------
+
+    .END
+
+
+
+
+
+
+
+
+
+
+

Added: scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,372 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include "gbampsave.h"
+#include "gba_nds_fat.h"
+
+/////////////////////////
+// GBAMP Save File
+/////////////////////////
+
+GBAMPSaveFile::GBAMPSaveFile(char* name, bool saveOrLoad) {
+	handle = DS::std_fopen(name, saveOrLoad? "w": "r");
+	//consolePrintf("%s handle is %d\n", name, handle);
+//	consolePrintf("Created %s\n", name);
+	bufferPos = 0;
+	saveSize = 0;
+	flushed = 0;
+}
+
+GBAMPSaveFile::~GBAMPSaveFile() {
+	flushSaveBuffer();
+	DS::std_fclose(handle);
+}
+
+uint32 GBAMPSaveFile::read(void *buf, uint32 size) {
+	saveSize += size;
+//	consolePrintf("Read %d %d ", size, saveSize);
+	return DS::std_fread(buf, 1, size, handle);
+}
+
+bool GBAMPSaveFile::eos() const {
+	return DS::std_feof(handle);
+}
+
+void GBAMPSaveFile::skip(uint32 bytes) {
+	DS::std_fseek(handle, bytes, SEEK_CUR);
+}
+
+void GBAMPSaveFile::flushSaveBuffer() {
+	if (bufferPos != 0) {
+//		consolePrintf("Flushing %d bytes\n", bufferPos);
+		flushed += bufferPos;
+		DS::std_fwrite(buffer, 1, bufferPos, handle);
+		bufferPos = 0;
+	}
+}
+
+uint32 GBAMPSaveFile::pos() const {
+	return DS::std_ftell(handle);
+}
+
+uint32 GBAMPSaveFile::size() const {
+	int position = pos();
+	DS::std_fseek(handle, 0, SEEK_END);
+	int size = DS::std_ftell(handle);
+	DS::std_fseek(handle, position, SEEK_SET);
+	return size;
+}
+
+void GBAMPSaveFile::seek(int32 pos, int whence) {
+	DS::std_fseek(handle, pos, whence);
+}
+
+
+uint32 GBAMPSaveFile::write(const void *buf, uint32 size) {
+	if (bufferPos + size > SAVE_BUFFER_SIZE) {
+		flushSaveBuffer();
+		saveSize += size;
+		DS::std_fwrite(buf, 1, size, handle);
+/*		int pos = 0;
+		
+		int rest = SAVE_BUFFER_SIZE - bufferPos;
+		memcpy(buffer + bufferPos, buf, rest);
+		bufferPos = 512;
+		pos += rest;
+		flushSaveBuffer();		
+		size -= rest;
+//		consolePrintf("First section: %d\n", rest);
+		
+		while (size >= 512) {
+			DS::std_fwrite(((char *) (buf)) + pos, 1, 512, handle);
+			size -= 512;
+			pos += 512;
+//			consolePrintf("Full chunk, %d left ", size);
+		}
+		
+		bufferPos = 0;
+		memcpy(buffer + bufferPos, ((char *) (buf)) + pos, size);
+		bufferPos += size;
+//		consolePrintf("%d left in buffer ", bufferPos);*/
+		
+	} else {
+	
+		memcpy(buffer + bufferPos, buf, size);
+		bufferPos += size;
+		
+		saveSize += size;
+	}
+	
+//	if ((size > 100) || (size <= 0)) consolePrintf("Write %d bytes\n", size);
+	return size;
+}
+
+
+//////////////////////////
+// GBAMP Save File Manager
+//////////////////////////
+
+GBAMPSaveFileManager::GBAMPSaveFileManager() {
+
+}
+
+GBAMPSaveFileManager::~GBAMPSaveFileManager() {
+
+}
+
+Common::SaveFile* GBAMPSaveFileManager::openSavefile(char const* name, bool saveOrLoad) {
+	char fileSpec[128];
+	
+	strcpy(fileSpec, getSavePath());
+	
+	if (fileSpec[strlen(fileSpec) - 1] == '/') {
+		sprintf(fileSpec, "%s%s", getSavePath(), name);
+	} else {
+		sprintf(fileSpec, "%s/%s", getSavePath(), name);
+	}
+	
+//	consolePrintf(fileSpec);
+
+	return new GBAMPSaveFile(fileSpec, saveOrLoad);
+}
+
+void GBAMPSaveFileManager::listSavefiles(char const* prefix, bool* marks, int num) {
+	enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
+	char name[128];
+	char path[128];
+	
+	DS::std_cwd((char *) getSavePath());
+	
+	int fileType = FAT_FindFirstFile(name);
+	
+	for (int r = 0; r < num; r++) {
+		marks[r] = false;
+	}
+	
+	do {
+	
+		if (fileType == TYPE_FILE) {
+
+			FAT_GetLongFilename(name);
+			
+			for (int r = 0; r < num; r++) {
+				char str[128];
+				
+				
+				sprintf(str, "%s%02d", prefix, r);
+//				consolePrintf("%s != %s", str, name);
+				if (!stricmp(str, name)) {
+					marks[r] = true;
+//					consolePrintf("Matched %d", r);
+				}
+				
+			}
+			
+		}
+	
+	} while ((fileType = FAT_FindNextFile(name)));
+	
+	FAT_chdir("/");
+}
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include "gbampsave.h"
+#include "gba_nds_fat.h"
+
+/////////////////////////
+// GBAMP Save File
+/////////////////////////
+
+GBAMPSaveFile::GBAMPSaveFile(char* name, bool saveOrLoad) {
+	handle = DS::std_fopen(name, saveOrLoad? "w": "r");
+	//consolePrintf("%s handle is %d\n", name, handle);
+//	consolePrintf("Created %s\n", name);
+	bufferPos = 0;
+	saveSize = 0;
+	flushed = 0;
+}
+
+GBAMPSaveFile::~GBAMPSaveFile() {
+	flushSaveBuffer();
+	DS::std_fclose(handle);
+}
+
+uint32 GBAMPSaveFile::read(void *buf, uint32 size) {
+	saveSize += size;
+//	consolePrintf("Read %d %d ", size, saveSize);
+	return DS::std_fread(buf, 1, size, handle);
+}
+
+bool GBAMPSaveFile::eos() const {
+	return DS::std_feof(handle);
+}
+
+void GBAMPSaveFile::skip(uint32 bytes) {
+	DS::std_fseek(handle, bytes, SEEK_CUR);
+}
+
+void GBAMPSaveFile::flushSaveBuffer() {
+	if (bufferPos != 0) {
+//		consolePrintf("Flushing %d bytes\n", bufferPos);
+		flushed += bufferPos;
+		DS::std_fwrite(buffer, 1, bufferPos, handle);
+		bufferPos = 0;
+	}
+}
+
+uint32 GBAMPSaveFile::pos() const {
+	return DS::std_ftell(handle);
+}
+
+uint32 GBAMPSaveFile::size() const {
+	int position = pos();
+	DS::std_fseek(handle, 0, SEEK_END);
+	int size = DS::std_ftell(handle);
+	DS::std_fseek(handle, position, SEEK_SET);
+	return size;
+}
+
+void GBAMPSaveFile::seek(int32 pos, int whence) {
+	DS::std_fseek(handle, pos, whence);
+}
+
+
+uint32 GBAMPSaveFile::write(const void *buf, uint32 size) {
+	if (bufferPos + size > SAVE_BUFFER_SIZE) {
+		flushSaveBuffer();
+		saveSize += size;
+		DS::std_fwrite(buf, 1, size, handle);
+/*		int pos = 0;
+		
+		int rest = SAVE_BUFFER_SIZE - bufferPos;
+		memcpy(buffer + bufferPos, buf, rest);
+		bufferPos = 512;
+		pos += rest;
+		flushSaveBuffer();		
+		size -= rest;
+//		consolePrintf("First section: %d\n", rest);
+		
+		while (size >= 512) {
+			DS::std_fwrite(((char *) (buf)) + pos, 1, 512, handle);
+			size -= 512;
+			pos += 512;
+//			consolePrintf("Full chunk, %d left ", size);
+		}
+		
+		bufferPos = 0;
+		memcpy(buffer + bufferPos, ((char *) (buf)) + pos, size);
+		bufferPos += size;
+//		consolePrintf("%d left in buffer ", bufferPos);*/
+		
+	} else {
+	
+		memcpy(buffer + bufferPos, buf, size);
+		bufferPos += size;
+		
+		saveSize += size;
+	}
+	
+//	if ((size > 100) || (size <= 0)) consolePrintf("Write %d bytes\n", size);
+	return size;
+}
+
+
+//////////////////////////
+// GBAMP Save File Manager
+//////////////////////////
+
+GBAMPSaveFileManager::GBAMPSaveFileManager() {
+
+}
+
+GBAMPSaveFileManager::~GBAMPSaveFileManager() {
+
+}
+
+Common::SaveFile* GBAMPSaveFileManager::openSavefile(char const* name, bool saveOrLoad) {
+	char fileSpec[128];
+	
+	strcpy(fileSpec, getSavePath());
+	
+	if (fileSpec[strlen(fileSpec) - 1] == '/') {
+		sprintf(fileSpec, "%s%s", getSavePath(), name);
+	} else {
+		sprintf(fileSpec, "%s/%s", getSavePath(), name);
+	}
+	
+//	consolePrintf(fileSpec);
+
+	return new GBAMPSaveFile(fileSpec, saveOrLoad);
+}
+
+void GBAMPSaveFileManager::listSavefiles(char const* prefix, bool* marks, int num) {
+	enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
+	char name[128];
+	char path[128];
+	
+	DS::std_cwd((char *) getSavePath());
+	
+	int fileType = FAT_FindFirstFile(name);
+	
+	for (int r = 0; r < num; r++) {
+		marks[r] = false;
+	}
+	
+	do {
+	
+		if (fileType == TYPE_FILE) {
+
+			FAT_GetLongFilename(name);
+			
+			for (int r = 0; r < num; r++) {
+				char str[128];
+				
+				
+				sprintf(str, "%s%02d", prefix, r);
+//				consolePrintf("%s != %s", str, name);
+				if (!stricmp(str, name)) {
+					marks[r] = true;
+//					consolePrintf("Matched %d", r);
+				}
+				
+			}
+			
+		}
+	
+	} while ((fileType = FAT_FindNextFile(name)));
+	
+	FAT_chdir("/");
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,164 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _GBAMPSAVE_H_
+#define _GBAMPSAVE_H_
+
+#include "stdafx.h"
+#include "system.h"
+
+#define SAVE_BUFFER_SIZE 100000
+
+class GBAMPSaveFile : public Common::SaveFile {
+	FILE* handle;
+	char buffer[SAVE_BUFFER_SIZE];
+	int bufferPos;
+	int saveSize;
+	int flushed;
+
+public:
+	GBAMPSaveFile(char* name, bool saveOrLoad);
+	~GBAMPSaveFile();
+		
+	virtual uint32 read(void *buf, uint32 size);
+	virtual uint32 write(const void *buf, uint32 size);
+	
+	virtual bool eos() const;
+	virtual void skip(uint32 bytes);
+
+	virtual uint32 pos() const;
+	virtual uint32 size() const;
+	virtual void seek(int32 pos, int whence);
+	
+	void flushSaveBuffer();
+	
+	virtual bool isOpen() const {
+		return true;
+	}
+};
+
+
+class GBAMPSaveFileManager : public Common::SaveFileManager {
+
+	
+public:
+	GBAMPSaveFileManager();
+	~GBAMPSaveFileManager();
+	
+//	static GBAMPSaveFileManager* instance() { return instancePtr; }
+
+	Common::SaveFile *openSavefile(const char *filename, bool saveOrLoad);
+	
+	virtual Common::OutSaveFile* openForSaving(const char* filename) { return openSavefile(filename, true); }
+	virtual Common::InSaveFile* openForLoading(const char* filename) { return openSavefile(filename, false); }
+	
+	
+	void listSavefiles(const char *prefix, bool *marks, int num);
+	
+	void deleteFile(char* name);
+	void listFiles();
+	
+protected:
+	Common::SaveFile *makeSaveFile(const char *filename, bool saveOrLoad);
+};
+
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _GBAMPSAVE_H_
+#define _GBAMPSAVE_H_
+
+#include "stdafx.h"
+#include "system.h"
+
+#define SAVE_BUFFER_SIZE 100000
+
+class GBAMPSaveFile : public Common::SaveFile {
+	FILE* handle;
+	char buffer[SAVE_BUFFER_SIZE];
+	int bufferPos;
+	int saveSize;
+	int flushed;
+
+public:
+	GBAMPSaveFile(char* name, bool saveOrLoad);
+	~GBAMPSaveFile();
+		
+	virtual uint32 read(void *buf, uint32 size);
+	virtual uint32 write(const void *buf, uint32 size);
+	
+	virtual bool eos() const;
+	virtual void skip(uint32 bytes);
+
+	virtual uint32 pos() const;
+	virtual uint32 size() const;
+	virtual void seek(int32 pos, int whence);
+	
+	void flushSaveBuffer();
+	
+	virtual bool isOpen() const {
+		return true;
+	}
+};
+
+
+class GBAMPSaveFileManager : public Common::SaveFileManager {
+
+	
+public:
+	GBAMPSaveFileManager();
+	~GBAMPSaveFileManager();
+	
+//	static GBAMPSaveFileManager* instance() { return instancePtr; }
+
+	Common::SaveFile *openSavefile(const char *filename, bool saveOrLoad);
+	
+	virtual Common::OutSaveFile* openForSaving(const char* filename) { return openSavefile(filename, true); }
+	virtual Common::InSaveFile* openForLoading(const char* filename) { return openSavefile(filename, false); }
+	
+	
+	void listSavefiles(const char *prefix, bool *marks, int num);
+	
+	void deleteFile(char* name);
+	void listFiles();
+	
+protected:
+	Common::SaveFile *makeSaveFile(const char *filename, bool saveOrLoad);
+};
+
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/gbampsave.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/mad/readme.txt
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/mad/readme.txt	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/mad/readme.txt	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,2 @@
+Put mad.h here if you are compiling with Madlib support enabled.
+Put mad.h here if you are compiling with Madlib support enabled.
\ No newline at end of file


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/mad/readme.txt
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,968 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#include "stdafx.h"
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "system.h"
+
+#include "common/util.h"
+#include "common/rect.h"
+#include "common/savefile.h"
+
+#include "osystem_ds.h"
+#include "nds.h"
+#include "dsmain.h"
+#include "nds/registers_alt.h"
+#include "config-manager.h"
+#include "common/str.h"
+#include "cdaudio.h"
+#include "graphics/surface.h"
+
+OSystem_DS* OSystem_DS::_instance = NULL;
+
+OSystem_DS::OSystem_DS()
+{
+	eventNum = 0;
+	lastPenFrame = 0;
+	queuePos = 0;
+	_instance = this;
+}
+
+OSystem_DS::~OSystem_DS() {
+}
+
+void OSystem_DS::initBackend() {
+	ConfMan.setInt("autosave_period", 0);
+	ConfMan.setBool("FM_medium_quality", true);
+}
+
+bool OSystem_DS::hasFeature(Feature f) {
+//	consolePrintf("hasfeature\n");
+	return (f == kFeatureVirtualKeyboard);
+}
+
+void OSystem_DS::setFeatureState(Feature f, bool enable) {
+//	consolePrintf("setfeature f=%d e=%d\n", f, enable);
+	if (f == kFeatureVirtualKeyboard) DS::setKeyboardIcon(enable);
+}
+
+bool OSystem_DS::getFeatureState(Feature f) {
+//	consolePrintf("getfeat\n");
+	if (f == kFeatureVirtualKeyboard) return DS::getKeyboardIcon();
+	return false;
+}
+
+const OSystem::GraphicsMode* OSystem_DS::getSupportedGraphicsModes() const {
+	return s_supportedGraphicsModes;
+}
+
+
+int OSystem_DS::getDefaultGraphicsMode() const {
+	return 0;
+}
+
+bool OSystem_DS::setGraphicsMode(int mode) {
+	return true;
+}
+
+bool OSystem_DS::setGraphicsMode(const char *name) {
+//	consolePrintf("Set gfx mode %s\n", name);
+	return true;
+}
+
+int OSystem_DS::getGraphicsMode() const {
+	return -1;
+}
+
+void OSystem_DS::initSize(uint width, uint height) {
+//	consolePrintf("Set gfx mode %d x %d\n", width, height);
+	DS::setGameSize(width, height);
+}
+
+int16 OSystem_DS::getHeight() {
+	return 200;
+}
+
+int16 OSystem_DS::getWidth() {
+	return 320;
+}
+
+void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
+//	consolePrintf("Set palette %d, %d colours\n", start, num);
+	if (!DS::getIsDisplayMode8Bit()) return;
+	
+	for (unsigned int r = start; r < start + num; r++) {
+		int red = *colors;
+		int green = *(colors + 1);
+		int blue = *(colors + 2);
+		
+		red >>= 3;
+		green >>= 3;
+		blue >>= 3;
+		
+		BG_PALETTE[r] = red | (green << 5) | (blue << 10);
+		if (!DS::getKeyboardEnable()) {
+			BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10);
+		}
+//		if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue);
+		
+		colors += 4;
+	}
+}
+
+
+void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) {
+//	consolePrintf("Grabpalette");
+	
+	for (unsigned int r = start; r < start + num; r++) {
+		*colors++ = (BG_PALETTE[r] & 0x001F) << 3;
+		*colors++ = (BG_PALETTE[r] & 0x03E0) >> 5 << 3;
+		*colors++ = (BG_PALETTE[r] & 0x7C00) >> 10 << 3;
+	}
+}
+
+
+void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h)
+{
+//	consolePrintf("Copy rect %d, %d   %d, %d ", x, y, w, h);
+	
+	if (w <= 1) return;
+	if (h < 0) return;
+	if (!DS::getIsDisplayMode8Bit()) return;
+	
+	u16* bgSub = (u16 *) BG_GFX_SUB;
+	u16* bg = (u16 *) DS::get8BitBackBuffer();
+	u16* src = (u16 *) buf;
+	
+	if (DS::getKeyboardEnable()) {
+	
+		for (int dy = y; dy < y + h; dy++) {
+			u16* dest = bg + (dy << 8) + (x >> 1);
+		
+			DC_FlushRange(src, w << 1);
+			DC_FlushRange(dest, w << 1);
+			dmaCopyHalfWords(3, src, dest, w);
+					
+			src += pitch >> 1;
+		}
+	
+	} else {
+		for (int dy = y; dy < y + h; dy++) {
+			u16* dest1 = bg + (dy << 8) + (x >> 1);
+			u16* dest2 = bgSub + (dy << 8) + (x >> 1);
+			
+			DC_FlushRange(src, w << 1);
+			DC_FlushRange(dest1, w << 1);
+			DC_FlushRange(dest2, w << 1);
+					
+			dmaCopyHalfWords(3, src, dest1, w);
+			dmaCopyHalfWords(3, src, dest2, w);
+					
+			src += pitch >> 1;
+		}
+	}
+	
+//	consolePrintf("Done\n");
+	
+			
+	
+}
+
+void OSystem_DS::updateScreen()
+{
+	DS::displayMode16BitFlipBuffer();
+	DS::doSoundCallback();
+//	DS::doTimerCallback();
+	DS::addEventsToQueue();
+}
+
+void OSystem_DS::setShakePos(int shakeOffset) {
+	DS::setShakePos(shakeOffset);
+}
+
+void OSystem_DS::showOverlay ()
+{
+//	consolePrintf("showovl\n");
+	DS::displayMode16Bit();
+}
+
+void OSystem_DS::hideOverlay ()
+{
+	DS::displayMode8Bit();
+}
+
+void OSystem_DS::clearOverlay ()
+{
+	memset((u16 *) DS::get16BitBackBuffer(), 0, 512 * 256 * 2);
+//	consolePrintf("clearovl\n");
+}
+
+void OSystem_DS::grabOverlay (OverlayColor *buf, int pitch)
+{
+//	consolePrintf("grabovl\n");
+}
+
+void OSystem_DS::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h)
+{
+	u16* bg = (u16 *) DS::get16BitBackBuffer();
+	u16* src = (u16 *) buf;
+		
+//	if (x + w > 256) w = 256 - x;
+	//if (x + h > 256) h = 256 - y;
+
+//	consolePrintf("Copy rect ovl %d, %d   %d, %d  %d\n", x, y, w, h, pitch);
+
+	
+	
+	for (int dy = y; dy < y + h; dy++) {
+		
+		
+		// Slow but save copy:
+		for (int dx = x; dx < x + w; dx++) {
+			
+			*(bg + (dy * 512) + dx) = *src;
+			//if ((*src) != 0) consolePrintf("%d,%d: %d   ", dx, dy, *src);
+			//consolePrintf("%d,", *src);
+			src++;
+		}
+		src += (pitch - w);
+		
+		// Fast but broken copy: (why?)
+		/*
+		REG_IME = 0;
+		dmaCopy(src, bg + (dy << 9) + x, w * 2);
+		REG_IME = 1;
+		
+		src += pitch;*/
+	}
+			
+//	consolePrintf("Copy rect ovl done");
+
+}
+
+int16 OSystem_DS::getOverlayHeight()
+{
+//	consolePrintf("getovlheight\n");
+	return getHeight();
+}
+
+int16 OSystem_DS::getOverlayWidth()
+{
+//	consolePrintf("getovlwid\n");
+	return getWidth();
+}
+
+	
+bool OSystem_DS::showMouse(bool visible)
+{
+	return true;
+}
+
+void OSystem_DS::warpMouse(int x, int y)
+{
+}
+
+void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) {
+	DS::setCursorIcon(buf, w, h, keycolor);
+}
+
+void OSystem_DS::addEvent(Event& e) {
+	eventQueue[queuePos++] = e;
+}
+
+bool OSystem_DS::pollEvent(Event &event)
+{
+
+	if (lastPenFrame != DS::getMillis()) {
+
+		if (eventNum == queuePos) {
+			eventNum = 0;
+			queuePos = 0;
+			// Bodge - this last event seems to be processed sometimes and not others.
+			// So we make it something harmless which won't cause any adverse effects.
+			event.type = EVENT_KEYUP;
+			event.kbd.ascii = 0;
+			event.kbd.keycode = 0;
+			event.kbd.flags = 0;
+			return false;
+		} else {
+			event = eventQueue[eventNum++];
+			return true;
+		}
+	}
+	
+	return false;
+
+/*	if (lastPenFrame != DS::getMillis()) {
+		if ((eventNum == 0)) {
+			event.type = EVENT_MOUSEMOVE;
+			event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+			eventNum = 1;
+			return true;
+		}
+		if (eventNum == 1) {
+			eventNum = 0;
+			lastPenFrame = DS::getMillis();
+			if (DS::getPenDown()) {	
+				event.type = EVENT_LBUTTONDOWN;
+				event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+				consolePrintf("Down %d, %d  ", event.mouse.x, event.mouse.y);
+				return true;
+			} else if (DS::getPenReleased()) {
+				event.type = EVENT_LBUTTONUP;
+				event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+				consolePrintf("Up %d, %d ", event.mouse.x, event.mouse.y);
+				return true;
+			} else {
+				return false;
+			}
+		}
+	}*/
+
+	return false;
+}
+
+uint32 OSystem_DS::getMillis()
+{
+	return DS::getMillis();
+}
+
+void OSystem_DS::delayMillis(uint msecs)
+{
+	int st = getMillis();
+	DS::addEventsToQueue();
+	DS::CD::update();
+	
+	DS::doSoundCallback();
+	while (st + msecs >= getMillis()) {
+		DS::doSoundCallback();
+	}
+	
+	DS::doTimerCallback();
+	DS::checkSleepMode();
+	DS::addEventsToQueue();
+}
+
+void OSystem_DS::setTimerCallback(TimerProc callback, int interval)
+{
+//	consolePrintf("Settimercallback interval=%d\n", interval);
+	DS::setTimerCallback(callback, interval);
+}
+
+OSystem::MutexRef OSystem_DS::createMutex(void)
+{
+	return NULL;
+}
+
+void OSystem_DS::lockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_DS::unlockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_DS::deleteMutex(MutexRef mutex)
+{
+}
+
+bool OSystem_DS::setSoundCallback(SoundProc proc, void *param)
+{
+//	consolePrintf("Setsoundcallback");
+	DS::setSoundProc(proc, param);
+	return true;
+}
+
+void OSystem_DS::clearSoundCallback()
+{
+	consolePrintf("Clearing sound callback");
+//	DS::setSoundProc(NULL, NULL);
+}
+
+int OSystem_DS::getOutputSampleRate() const
+{
+	return 11025;
+}
+
+bool OSystem_DS::openCD(int drive)
+{
+	return DS::CD::checkCD();
+}
+
+bool OSystem_DS::pollCD()
+{
+	return DS::CD::isPlaying();
+}
+
+void OSystem_DS::playCD(int track, int num_loops, int start_frame, int duration)
+{
+	DS::CD::playTrack(track, num_loops, start_frame, duration);
+}
+
+void OSystem_DS::stopCD()
+{
+	DS::CD::stopTrack();
+}
+
+void OSystem_DS::updateCD()
+{
+}
+
+void OSystem_DS::quit()
+{
+/*	consolePrintf("Soft resetting...");
+	IPC->reset = 1;
+	REG_IE = 0;
+	
+	asm("swi 0x26\n");
+	swiSoftReset();*/
+}
+
+void OSystem_DS::setWindowCaption(const char *caption)
+{
+}
+
+void OSystem_DS::displayMessageOnOSD(const char *msg)
+{
+}
+
+Common::SaveFileManager* OSystem_DS::getSavefileManager()
+{
+	bool forceSram;
+
+	if (ConfMan.hasKey("forcesramsave", "ds")) {
+		forceSram = ConfMan.getBool("forcesramsave", "ds");
+	} else {
+		forceSram = false;
+	}
+	if (forceSram) { 
+		consolePrintf("Using SRAM save method!\n");
+	}
+	
+	if (DS::isGBAMPAvailable() && (!forceSram)) {
+		return &mpSaveManager;
+	} else {
+		return &saveManager;
+	}
+}
+
+bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) {
+	surf->create(DS::getGameWidth(), DS::getGameHeight(), 1);
+	memcpy(surf->pixels, DS::get8BitBackBuffer(), DS::getGameWidth() * DS::getGameHeight());
+	return true;
+}
+
+void OSystem_DS::setFocusRectangle(const Common::Rect& rect) {
+	DS::setTalkPos(rect.left + rect.width() / 2, rect.top + rect.height() / 2);
+}
+
+void OSystem_DS::clearFocusRectangle() {
+
+}
+
+
+OSystem *OSystem_DS_create() {
+	return new OSystem_DS();
+}
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#include "stdafx.h"
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "system.h"
+
+#include "common/util.h"
+#include "common/rect.h"
+#include "common/savefile.h"
+
+#include "osystem_ds.h"
+#include "nds.h"
+#include "dsmain.h"
+#include "nds/registers_alt.h"
+#include "config-manager.h"
+#include "common/str.h"
+#include "cdaudio.h"
+#include "graphics/surface.h"
+
+OSystem_DS* OSystem_DS::_instance = NULL;
+
+OSystem_DS::OSystem_DS()
+{
+	eventNum = 0;
+	lastPenFrame = 0;
+	queuePos = 0;
+	_instance = this;
+}
+
+OSystem_DS::~OSystem_DS() {
+}
+
+void OSystem_DS::initBackend() {
+	ConfMan.setInt("autosave_period", 0);
+	ConfMan.setBool("FM_medium_quality", true);
+}
+
+bool OSystem_DS::hasFeature(Feature f) {
+//	consolePrintf("hasfeature\n");
+	return (f == kFeatureVirtualKeyboard);
+}
+
+void OSystem_DS::setFeatureState(Feature f, bool enable) {
+//	consolePrintf("setfeature f=%d e=%d\n", f, enable);
+	if (f == kFeatureVirtualKeyboard) DS::setKeyboardIcon(enable);
+}
+
+bool OSystem_DS::getFeatureState(Feature f) {
+//	consolePrintf("getfeat\n");
+	if (f == kFeatureVirtualKeyboard) return DS::getKeyboardIcon();
+	return false;
+}
+
+const OSystem::GraphicsMode* OSystem_DS::getSupportedGraphicsModes() const {
+	return s_supportedGraphicsModes;
+}
+
+
+int OSystem_DS::getDefaultGraphicsMode() const {
+	return 0;
+}
+
+bool OSystem_DS::setGraphicsMode(int mode) {
+	return true;
+}
+
+bool OSystem_DS::setGraphicsMode(const char *name) {
+//	consolePrintf("Set gfx mode %s\n", name);
+	return true;
+}
+
+int OSystem_DS::getGraphicsMode() const {
+	return -1;
+}
+
+void OSystem_DS::initSize(uint width, uint height) {
+//	consolePrintf("Set gfx mode %d x %d\n", width, height);
+	DS::setGameSize(width, height);
+}
+
+int16 OSystem_DS::getHeight() {
+	return 200;
+}
+
+int16 OSystem_DS::getWidth() {
+	return 320;
+}
+
+void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
+//	consolePrintf("Set palette %d, %d colours\n", start, num);
+	if (!DS::getIsDisplayMode8Bit()) return;
+	
+	for (unsigned int r = start; r < start + num; r++) {
+		int red = *colors;
+		int green = *(colors + 1);
+		int blue = *(colors + 2);
+		
+		red >>= 3;
+		green >>= 3;
+		blue >>= 3;
+		
+		BG_PALETTE[r] = red | (green << 5) | (blue << 10);
+		if (!DS::getKeyboardEnable()) {
+			BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10);
+		}
+//		if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue);
+		
+		colors += 4;
+	}
+}
+
+
+void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) {
+//	consolePrintf("Grabpalette");
+	
+	for (unsigned int r = start; r < start + num; r++) {
+		*colors++ = (BG_PALETTE[r] & 0x001F) << 3;
+		*colors++ = (BG_PALETTE[r] & 0x03E0) >> 5 << 3;
+		*colors++ = (BG_PALETTE[r] & 0x7C00) >> 10 << 3;
+	}
+}
+
+
+void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h)
+{
+//	consolePrintf("Copy rect %d, %d   %d, %d ", x, y, w, h);
+	
+	if (w <= 1) return;
+	if (h < 0) return;
+	if (!DS::getIsDisplayMode8Bit()) return;
+	
+	u16* bgSub = (u16 *) BG_GFX_SUB;
+	u16* bg = (u16 *) DS::get8BitBackBuffer();
+	u16* src = (u16 *) buf;
+	
+	if (DS::getKeyboardEnable()) {
+	
+		for (int dy = y; dy < y + h; dy++) {
+			u16* dest = bg + (dy << 8) + (x >> 1);
+		
+			DC_FlushRange(src, w << 1);
+			DC_FlushRange(dest, w << 1);
+			dmaCopyHalfWords(3, src, dest, w);
+					
+			src += pitch >> 1;
+		}
+	
+	} else {
+		for (int dy = y; dy < y + h; dy++) {
+			u16* dest1 = bg + (dy << 8) + (x >> 1);
+			u16* dest2 = bgSub + (dy << 8) + (x >> 1);
+			
+			DC_FlushRange(src, w << 1);
+			DC_FlushRange(dest1, w << 1);
+			DC_FlushRange(dest2, w << 1);
+					
+			dmaCopyHalfWords(3, src, dest1, w);
+			dmaCopyHalfWords(3, src, dest2, w);
+					
+			src += pitch >> 1;
+		}
+	}
+	
+//	consolePrintf("Done\n");
+	
+			
+	
+}
+
+void OSystem_DS::updateScreen()
+{
+	DS::displayMode16BitFlipBuffer();
+	DS::doSoundCallback();
+//	DS::doTimerCallback();
+	DS::addEventsToQueue();
+}
+
+void OSystem_DS::setShakePos(int shakeOffset) {
+	DS::setShakePos(shakeOffset);
+}
+
+void OSystem_DS::showOverlay ()
+{
+//	consolePrintf("showovl\n");
+	DS::displayMode16Bit();
+}
+
+void OSystem_DS::hideOverlay ()
+{
+	DS::displayMode8Bit();
+}
+
+void OSystem_DS::clearOverlay ()
+{
+	memset((u16 *) DS::get16BitBackBuffer(), 0, 512 * 256 * 2);
+//	consolePrintf("clearovl\n");
+}
+
+void OSystem_DS::grabOverlay (OverlayColor *buf, int pitch)
+{
+//	consolePrintf("grabovl\n");
+}
+
+void OSystem_DS::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h)
+{
+	u16* bg = (u16 *) DS::get16BitBackBuffer();
+	u16* src = (u16 *) buf;
+		
+//	if (x + w > 256) w = 256 - x;
+	//if (x + h > 256) h = 256 - y;
+
+//	consolePrintf("Copy rect ovl %d, %d   %d, %d  %d\n", x, y, w, h, pitch);
+
+	
+	
+	for (int dy = y; dy < y + h; dy++) {
+		
+		
+		// Slow but save copy:
+		for (int dx = x; dx < x + w; dx++) {
+			
+			*(bg + (dy * 512) + dx) = *src;
+			//if ((*src) != 0) consolePrintf("%d,%d: %d   ", dx, dy, *src);
+			//consolePrintf("%d,", *src);
+			src++;
+		}
+		src += (pitch - w);
+		
+		// Fast but broken copy: (why?)
+		/*
+		REG_IME = 0;
+		dmaCopy(src, bg + (dy << 9) + x, w * 2);
+		REG_IME = 1;
+		
+		src += pitch;*/
+	}
+			
+//	consolePrintf("Copy rect ovl done");
+
+}
+
+int16 OSystem_DS::getOverlayHeight()
+{
+//	consolePrintf("getovlheight\n");
+	return getHeight();
+}
+
+int16 OSystem_DS::getOverlayWidth()
+{
+//	consolePrintf("getovlwid\n");
+	return getWidth();
+}
+
+	
+bool OSystem_DS::showMouse(bool visible)
+{
+	return true;
+}
+
+void OSystem_DS::warpMouse(int x, int y)
+{
+}
+
+void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) {
+	DS::setCursorIcon(buf, w, h, keycolor);
+}
+
+void OSystem_DS::addEvent(Event& e) {
+	eventQueue[queuePos++] = e;
+}
+
+bool OSystem_DS::pollEvent(Event &event)
+{
+
+	if (lastPenFrame != DS::getMillis()) {
+
+		if (eventNum == queuePos) {
+			eventNum = 0;
+			queuePos = 0;
+			// Bodge - this last event seems to be processed sometimes and not others.
+			// So we make it something harmless which won't cause any adverse effects.
+			event.type = EVENT_KEYUP;
+			event.kbd.ascii = 0;
+			event.kbd.keycode = 0;
+			event.kbd.flags = 0;
+			return false;
+		} else {
+			event = eventQueue[eventNum++];
+			return true;
+		}
+	}
+	
+	return false;
+
+/*	if (lastPenFrame != DS::getMillis()) {
+		if ((eventNum == 0)) {
+			event.type = EVENT_MOUSEMOVE;
+			event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+			eventNum = 1;
+			return true;
+		}
+		if (eventNum == 1) {
+			eventNum = 0;
+			lastPenFrame = DS::getMillis();
+			if (DS::getPenDown()) {	
+				event.type = EVENT_LBUTTONDOWN;
+				event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+				consolePrintf("Down %d, %d  ", event.mouse.x, event.mouse.y);
+				return true;
+			} else if (DS::getPenReleased()) {
+				event.type = EVENT_LBUTTONUP;
+				event.mouse = Common::Point(DS::getPenX(), DS::getPenY());
+				consolePrintf("Up %d, %d ", event.mouse.x, event.mouse.y);
+				return true;
+			} else {
+				return false;
+			}
+		}
+	}*/
+
+	return false;
+}
+
+uint32 OSystem_DS::getMillis()
+{
+	return DS::getMillis();
+}
+
+void OSystem_DS::delayMillis(uint msecs)
+{
+	int st = getMillis();
+	DS::addEventsToQueue();
+	DS::CD::update();
+	
+	DS::doSoundCallback();
+	while (st + msecs >= getMillis()) {
+		DS::doSoundCallback();
+	}
+	
+	DS::doTimerCallback();
+	DS::checkSleepMode();
+	DS::addEventsToQueue();
+}
+
+void OSystem_DS::setTimerCallback(TimerProc callback, int interval)
+{
+//	consolePrintf("Settimercallback interval=%d\n", interval);
+	DS::setTimerCallback(callback, interval);
+}
+
+OSystem::MutexRef OSystem_DS::createMutex(void)
+{
+	return NULL;
+}
+
+void OSystem_DS::lockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_DS::unlockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_DS::deleteMutex(MutexRef mutex)
+{
+}
+
+bool OSystem_DS::setSoundCallback(SoundProc proc, void *param)
+{
+//	consolePrintf("Setsoundcallback");
+	DS::setSoundProc(proc, param);
+	return true;
+}
+
+void OSystem_DS::clearSoundCallback()
+{
+	consolePrintf("Clearing sound callback");
+//	DS::setSoundProc(NULL, NULL);
+}
+
+int OSystem_DS::getOutputSampleRate() const
+{
+	return 11025;
+}
+
+bool OSystem_DS::openCD(int drive)
+{
+	return DS::CD::checkCD();
+}
+
+bool OSystem_DS::pollCD()
+{
+	return DS::CD::isPlaying();
+}
+
+void OSystem_DS::playCD(int track, int num_loops, int start_frame, int duration)
+{
+	DS::CD::playTrack(track, num_loops, start_frame, duration);
+}
+
+void OSystem_DS::stopCD()
+{
+	DS::CD::stopTrack();
+}
+
+void OSystem_DS::updateCD()
+{
+}
+
+void OSystem_DS::quit()
+{
+/*	consolePrintf("Soft resetting...");
+	IPC->reset = 1;
+	REG_IE = 0;
+	
+	asm("swi 0x26\n");
+	swiSoftReset();*/
+}
+
+void OSystem_DS::setWindowCaption(const char *caption)
+{
+}
+
+void OSystem_DS::displayMessageOnOSD(const char *msg)
+{
+}
+
+Common::SaveFileManager* OSystem_DS::getSavefileManager()
+{
+	bool forceSram;
+
+	if (ConfMan.hasKey("forcesramsave", "ds")) {
+		forceSram = ConfMan.getBool("forcesramsave", "ds");
+	} else {
+		forceSram = false;
+	}
+	if (forceSram) { 
+		consolePrintf("Using SRAM save method!\n");
+	}
+	
+	if (DS::isGBAMPAvailable() && (!forceSram)) {
+		return &mpSaveManager;
+	} else {
+		return &saveManager;
+	}
+}
+
+bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) {
+	surf->create(DS::getGameWidth(), DS::getGameHeight(), 1);
+	memcpy(surf->pixels, DS::get8BitBackBuffer(), DS::getGameWidth() * DS::getGameHeight());
+	return true;
+}
+
+void OSystem_DS::setFocusRectangle(Common::Rect& rect) {
+	DS::setTalkPos(rect.left + rect.width() / 2, rect.top + rect.height() / 2);
+}
+
+void OSystem_DS::clearFocusRectangle() {
+
+}
+
+
+OSystem *OSystem_DS_create() {
+	return new OSystem_DS();
+}
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,284 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ 
+#ifndef _OSYSTEM_DS_H_
+#define _OSYSTEM_DS_H_
+#include "common/system.h"
+#include "nds.h"
+#include "ramsave.h"
+#include "gbampsave.h"
+
+class OSystem_DS : public OSystem {
+public:
+	static OSystem_DS *instance() { return _instance; }
+	int eventNum;
+	int lastPenFrame;
+	
+	Event eventQueue[64];
+	int queuePos;
+	
+	DSSaveFileManager saveManager;
+	GBAMPSaveFileManager mpSaveManager;
+	
+	static OSystem_DS* _instance;
+
+public:
+
+	OSystem_DS();
+	virtual ~OSystem_DS();
+
+	virtual bool hasFeature(Feature f);
+	virtual void setFeatureState(Feature f, bool enable);
+	virtual bool getFeatureState(Feature f);
+	virtual const GraphicsMode *getSupportedGraphicsModes() const;
+	virtual int getDefaultGraphicsMode() const;
+	virtual bool setGraphicsMode(int mode);
+	bool setGraphicsMode(const char *name);
+	virtual int getGraphicsMode() const;
+	virtual void initSize(uint width, uint height);
+	virtual int16 getHeight();
+	virtual int16 getWidth();
+	virtual void setPalette(const byte *colors, uint start, uint num);
+	virtual void grabPalette(unsigned char* colors, uint start, uint num);
+
+	virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+	virtual void updateScreen();
+	virtual void setShakePos(int shakeOffset);
+
+	virtual void showOverlay();
+	virtual void hideOverlay();
+	virtual void clearOverlay();
+	virtual void grabOverlay(OverlayColor *buf, int pitch);
+	virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+	virtual int16 getOverlayHeight();
+	virtual int16 getOverlayWidth();
+
+	inline virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b);
+	inline virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b);
+	
+	virtual bool showMouse(bool visible);
+
+	virtual void warpMouse(int x, int y);
+	virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetCursorScale = 1);
+
+	virtual bool pollEvent(Event &event);
+	virtual uint32 getMillis();
+	virtual void delayMillis(uint msecs);
+
+	virtual void setTimerCallback(TimerProc callback, int interval);
+
+	virtual MutexRef createMutex(void);
+	virtual void lockMutex(MutexRef mutex);
+	virtual void unlockMutex(MutexRef mutex);
+	virtual void deleteMutex(MutexRef mutex);
+
+	virtual bool setSoundCallback(SoundProc proc, void *param);
+	virtual void clearSoundCallback();
+	virtual int getOutputSampleRate() const;
+
+	virtual bool openCD(int drive);
+	virtual bool pollCD();
+
+	virtual void playCD(int track, int num_loops, int start_frame, int duration);
+	virtual void stopCD();
+	virtual void updateCD();
+
+	virtual void quit();
+
+	virtual void setWindowCaption(const char *caption);
+
+	virtual void displayMessageOnOSD(const char *msg);
+
+	virtual Common::SaveFileManager *getSavefileManager();
+	
+	void addEvent(Event& e);
+	bool isEventQueueEmpty() { return queuePos == 0; }
+	
+	virtual bool grabRawScreen(Graphics::Surface* surf);
+	
+	virtual void setFocusRectangle(const Common::Rect& rect);
+	
+	virtual void clearFocusRectangle();
+	
+	virtual void initBackend();
+};
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+	{0, 0, 0},
+};
+
+OverlayColor OSystem_DS::RGBToColor(uint8 r, uint8 g, uint8 b)
+{
+	return 0x8000 | (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 5);
+	//consolePrintf("rgbtocol\n");
+	return 0;
+}
+
+void OSystem_DS::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b)
+{
+	r = (color & 0x001F) << 3;
+	g = (color & 0x03E0) >> 5 << 3;
+	b = (color & 0x7C00) >> 10 << 3;
+	//consolePrintf("coltorgb\n");
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+ 
+#ifndef _OSYSTEM_DS_H_
+#define _OSYSTEM_DS_H_
+#include "common/system.h"
+#include "nds.h"
+#include "ramsave.h"
+#include "gbampsave.h"
+
+class OSystem_DS : public OSystem {
+public:
+	static OSystem_DS *instance() { return _instance; }
+	int eventNum;
+	int lastPenFrame;
+	
+	Event eventQueue[64];
+	int queuePos;
+	
+	DSSaveFileManager saveManager;
+	GBAMPSaveFileManager mpSaveManager;
+	
+	static OSystem_DS* _instance;
+
+public:
+
+	OSystem_DS();
+	virtual ~OSystem_DS();
+
+	virtual bool hasFeature(Feature f);
+	virtual void setFeatureState(Feature f, bool enable);
+	virtual bool getFeatureState(Feature f);
+	virtual const GraphicsMode *getSupportedGraphicsModes() const;
+	virtual int getDefaultGraphicsMode() const;
+	virtual bool setGraphicsMode(int mode);
+	bool setGraphicsMode(const char *name);
+	virtual int getGraphicsMode() const;
+	virtual void initSize(uint width, uint height);
+	virtual int16 getHeight();
+	virtual int16 getWidth();
+	virtual void setPalette(const byte *colors, uint start, uint num);
+	virtual void grabPalette(unsigned char* colors, uint start, uint num);
+
+	virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+	virtual void updateScreen();
+	virtual void setShakePos(int shakeOffset);
+
+	virtual void showOverlay();
+	virtual void hideOverlay();
+	virtual void clearOverlay();
+	virtual void grabOverlay(OverlayColor *buf, int pitch);
+	virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+	virtual int16 getOverlayHeight();
+	virtual int16 getOverlayWidth();
+
+	inline virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b);
+	inline virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b);
+	
+	virtual bool showMouse(bool visible);
+
+	virtual void warpMouse(int x, int y);
+	virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetCursorScale = 1);
+
+	virtual bool pollEvent(Event &event);
+	virtual uint32 getMillis();
+	virtual void delayMillis(uint msecs);
+
+	virtual void setTimerCallback(TimerProc callback, int interval);
+
+	virtual MutexRef createMutex(void);
+	virtual void lockMutex(MutexRef mutex);
+	virtual void unlockMutex(MutexRef mutex);
+	virtual void deleteMutex(MutexRef mutex);
+
+	virtual bool setSoundCallback(SoundProc proc, void *param);
+	virtual void clearSoundCallback();
+	virtual int getOutputSampleRate() const;
+
+	virtual bool openCD(int drive);
+	virtual bool pollCD();
+
+	virtual void playCD(int track, int num_loops, int start_frame, int duration);
+	virtual void stopCD();
+	virtual void updateCD();
+
+	virtual void quit();
+
+	virtual void setWindowCaption(const char *caption);
+
+	virtual void displayMessageOnOSD(const char *msg);
+
+	virtual Common::SaveFileManager *getSavefileManager();
+	
+	void addEvent(Event& e);
+	bool isEventQueueEmpty() { return queuePos == 0; }
+	
+	virtual bool grabRawScreen(Graphics::Surface* surf);
+	
+	virtual void setFocusRectangle(Common::Rect& rect);
+	
+	virtual void clearFocusRectangle();
+	
+	virtual void initBackend();
+};
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+	{0, 0, 0},
+};
+
+OverlayColor OSystem_DS::RGBToColor(uint8 r, uint8 g, uint8 b)
+{
+	return 0x8000 | (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 5);
+	//consolePrintf("rgbtocol\n");
+	return 0;
+}
+
+void OSystem_DS::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b)
+{
+	r = (color & 0x001F) << 3;
+	g = (color & 0x03E0) >> 5 << 3;
+	b = (color & 0x7C00) >> 10 << 3;
+	//consolePrintf("coltorgb\n");
+}
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/osystem_ds.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/portdefs.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/portdefs.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/portdefs.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,84 @@
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include "portdefs.h"
+#include <string.h>
+#include "nds/dma.h"
+#include "osystem_ds.h"
+
+time_t DS_time(time_t) {
+	if (OSystem_DS::instance()) {
+		return 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+	} else {
+		return 0xABCD1234;
+	}
+}
+
+time_t DS_time(long* t) {
+	if (OSystem_DS::instance()) {
+		if (t) *t = 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+		return 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+	} else {
+		if (t) *t = 0xABCD1234;
+		return 0xABCD1234;
+	}
+}
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include "portdefs.h"
+#include <string.h>
+#include "nds/dma.h"
+#include "osystem_ds.h"
+
+time_t DS_time(time_t) {
+	if (OSystem_DS::instance()) {
+		return 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+	} else {
+		return 0xABCD1234;
+	}
+}
+
+time_t DS_time(long* t) {
+	if (OSystem_DS::instance()) {
+		if (t) *t = 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+		return 0xABCD1234 + (OSystem_DS::instance()->getMillis() / 1000);
+	} else {
+		if (t) *t = 0xABCD1234;
+		return 0xABCD1234;
+	}
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/portdefs.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/portdefs.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/portdefs.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/portdefs.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,100 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _PORTDEFS_H_
+#define _PORTDEFS_H_
+
+
+typedef unsigned char u8;
+typedef signed char s8;
+
+typedef unsigned short u16;
+typedef signed short s16;
+
+typedef unsigned int u32;
+typedef signed int s32;
+
+//#define double float
+
+
+#undef assert
+#define assert(expr) consolePrintf("Asserted!")
+//#define NO_DEBUG_MSGS
+#include "ds-fs.h"
+
+//#define debug(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__)
+//#define debug(fmt, ...) debug(0, fmt, ##__VA_ARGS__)
+#define time(t) DS_time(t)
+//#define memcpy(dest, src, size) DS_memcpy(dest, src, size)
+
+time_t DS_time(time_t* t);
+time_t DS_time(long* t);
+void* DS_memcpy(void* s1, void const* s2, size_t n);
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _PORTDEFS_H_
+#define _PORTDEFS_H_
+
+
+typedef unsigned char u8;
+typedef signed char s8;
+
+typedef unsigned short u16;
+typedef signed short s16;
+
+typedef unsigned int u32;
+typedef signed int s32;
+
+//#define double float
+
+
+#undef assert
+#define assert(expr) consolePrintf("Asserted!")
+//#define NO_DEBUG_MSGS
+#include "ds-fs.h"
+
+//#define debug(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__)
+//#define debug(fmt, ...) debug(0, fmt, ##__VA_ARGS__)
+#define time(t) DS_time(t)
+//#define memcpy(dest, src, size) DS_memcpy(dest, src, size)
+
+time_t DS_time(time_t* t);
+time_t DS_time(long* t);
+void* DS_memcpy(void* s1, void const* s2, size_t n);
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/portdefs.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/ramsave.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/ramsave.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/ramsave.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,918 @@
+/* Ramsave
+ * Copyright (C) 2002-2004 Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 
+ */
+ // Save in order 1,2,3,4,larger 2,5
+#include "stdafx.h"
+#include "system.h"
+#include "ramsave.h"
+#include "nds.h"
+#include "compressor/lz.h"
+
+#define CART_RAM ((vu8 *) (0x0A000000))
+
+DSSaveFile::DSSaveFile() {
+	ptr = 0;
+	saveCompressed = false;
+	save.isValid = false;
+	ownsData = false;
+	isOpenFlag = true;
+	isTempFile = false;
+}
+
+DSSaveFile::DSSaveFile(SCUMMSave* s, bool compressed, u8* data) {
+	save = *s;
+	saveData = data;
+	ptr = 0;
+	saveCompressed = compressed;
+	isOpenFlag = true;
+
+	if (saveCompressed) {
+		u8* uncompressed = new unsigned char[save.size];
+		if (!uncompressed) consolePrintf("Out of memory allocating %d!\n", save.size);
+		LZ_Uncompress(saveData, uncompressed, save.compressedSize);
+		saveData = uncompressed;
+		ownsData = true;
+		saveCompressed = false;
+//		consolePrintf("Decompressed. name=%s size=%d (%d)", save.name, save.size, save.compressedSize);
+		
+	} else {
+		ownsData = false;
+		origHeader = s;
+	}
+	
+	if (save.magic == (int) 0xBEEFCAFE) {
+		save.isValid = true;
+	} else {
+		save.isValid = false;
+	}
+	
+	isTempFile = false;
+}
+
+DSSaveFile::~DSSaveFile() {
+	if (!ownsData) {
+		*origHeader = save;
+		DSSaveFileManager::instance()->flushToSaveRAM();
+	}
+	if (ownsData) {
+		delete saveData;
+	}
+}
+
+bool DSSaveFile::loadFromSaveRAM(vu8* address) {
+	
+	SCUMMSave newSave;
+
+	for (int t = 0; t < (int) sizeof(newSave); t++) {
+		((char *) (&newSave))[t] = *(address + t);
+	}
+	
+	
+	if (newSave.magic == 0xBEEFCAFE) {
+		newSave.isValid = true;
+
+		*((u16 *) (0x4000204)) |= 0x3;
+		
+		saveData = new unsigned char[newSave.compressedSize];
+		
+		for (int t = 0; t < (int) newSave.compressedSize; t++) {
+			((char *) (saveData))[t] = *(address + t + sizeof(newSave));
+		}
+		
+		if (ownsData) delete this->saveData;
+		save = newSave;
+		saveCompressed = true;
+		this->saveData = saveData;
+		ownsData = true;
+		ptr = 0;
+		return true;
+	}
+	
+	return false;
+}
+
+void DSSaveFile::compress() {
+	if (!saveCompressed) {
+		unsigned char* compBuffer = new unsigned char[(save.size * 110) / 100];
+		int compSize = LZ_Compress((u8 *) saveData, compBuffer, save.size);
+		save.compressedSize = compSize;
+		
+		
+		
+		delete saveData;
+		
+		// Make the save smaller
+		saveData = (u8 *) realloc(compBuffer, save.compressedSize);
+		saveCompressed = true;
+	}
+}
+
+int DSSaveFile::saveToSaveRAM(vu8* address) {
+
+	unsigned char* compBuffer;
+	bool failed;
+	
+
+	int compSize;
+	
+	compress();
+	
+	compSize = save.compressedSize;
+	compBuffer = saveData;
+	
+	if (DSSaveFileManager::instance()->getBytesFree() >= getRamUsage()) {
+
+		DSSaveFileManager::instance()->addBytesFree(-getRamUsage());
+	
+		// Write header
+		for (int t = 0; t < sizeof(save); t++) {
+			while (*(address + t) != ((char *) (&save))[t]) {
+				*(address + t) = ((char *) (&save))[t];
+			}
+		}
+	
+		// Write compressed buffer
+		for (int t = sizeof(save); t < (int) sizeof(save) + compSize; t++) {
+			while (*(address + t) != compBuffer[t - sizeof(save)]) {
+				*(address + t) = compBuffer[t - sizeof(save)];
+			}
+		}
+		
+		failed = false;
+	} else {
+		failed = true;
+	}
+
+		
+	return failed? 0: compSize + sizeof(save);
+
+}
+
+void DSSaveFile::reset() {
+	ptr = 0;
+}
+
+uint32 DSSaveFile::read(void *buf, uint32 size) {
+	if (ptr + size > save.size) {
+		size = save.size - ptr;
+		if (size < 0) size = 0;
+	}
+	memcpy(buf, saveData + ptr, size);
+//	consolePrintf("byte: %d ", ((u8 *) (buf))[0]);
+	
+	ptr += size;
+	return size;
+}
+
+uint32 DSSaveFile::pos() const {
+	return ptr;
+}
+
+uint32 DSSaveFile::size() const {
+	return save.size;
+}
+
+void DSSaveFile::seek(int32 pos, int whence) {
+	switch (whence) {
+		case SEEK_SET: {
+			ptr = pos;
+			break;
+		}
+		case SEEK_CUR: {
+			ptr += pos;
+			break;
+		}
+		case SEEK_END: {
+			ptr = save.size - pos;
+			break;
+		}
+	}
+}
+
+bool DSSaveFile::eos() const {
+	return ptr >= (int) save.size;
+}
+
+void DSSaveFile::skip(uint32 bytes) {
+	ptr = ptr + bytes;
+	if (ptr > (int) save.size) ptr = save.size;
+}
+
+uint32 DSSaveFile::write(const void *buf, uint32 size) {
+
+	if (ptr + size > DS_MAX_SAVE_SIZE) {
+		size = DS_MAX_SAVE_SIZE - ptr;
+	}
+
+	memcpy(saveData + ptr, buf, size);
+	ptr += size;
+	save.size += size;
+	return size;
+}
+
+bool DSSaveFile::matches(char* prefix, int num) {
+	char str[16];
+	if (isValid()) {
+		sprintf(str, "%s%02d", prefix, num);
+		if (!strcmp(str, save.name)) {
+			return true;
+		} else {
+			return false;
+		}
+	} else {
+		return false;
+	}
+}
+
+bool DSSaveFile::matches(char* filename) {
+	if (isValid()) {
+		return !strcmp(save.name, filename);
+	} else {
+		return false;
+	}
+}
+	
+void DSSaveFile::setName(char *name) {
+	save.isValid = true;
+	save.magic = 0xBEEFCAFE;
+	ownsData = true;
+	save.size = 0;
+	save.compressedSize = 0;
+	saveData = new unsigned char[DS_MAX_SAVE_SIZE];
+	strcpy(save.name, name);
+	
+	if ((strstr(name, ".s99")) || (strstr(name, ".c"))) {
+		isTempFile = true;
+	} else {
+		isTempFile = false;
+	}
+}
+
+void DSSaveFile::clearData() {
+	save.size = 0;
+
+	if (saveCompressed) {
+		if (ownsData) {
+			delete saveData;
+			DSSaveFileManager::instance()->addBytesFree(getRamUsage());
+		}
+		saveData = new unsigned char[DS_MAX_SAVE_SIZE];
+		saveCompressed = false;
+		ownsData = true;
+	}
+
+}
+
+void DSSaveFile::deleteFile() {
+	if (isValid()) {
+		if (ownsData) {
+			DSSaveFileManager::instance()->addBytesFree(getRamUsage());
+			delete saveData;
+			saveData = NULL;
+		}
+		ptr = 0;
+		saveCompressed = false;
+		save.isValid = false;
+		ownsData = false;
+		isOpenFlag = true;
+	}
+}
+
+DSSaveFileManager::DSSaveFileManager() {
+	instancePtr = this;
+	
+	*((u16 *) (0x4000204)) |= 0x3;
+	swiWaitForVBlank();
+	
+	loadAllFromSRAM();
+}
+
+DSSaveFileManager::~DSSaveFileManager() {
+	instancePtr = NULL;
+}
+
+void DSSaveFileManager::loadAllFromSRAM() {
+	int addr = 1;
+	
+	for (int r = 0; r < 8; r++) {
+		gbaSave[r].deleteFile();
+	}
+
+	sramBytesFree = 65533;
+
+	// Try to find saves in save RAM
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].loadFromSaveRAM(CART_RAM + addr)) {
+			addr += gbaSave[r].getRamUsage();
+			sramBytesFree -= gbaSave[r].getRamUsage();
+		}
+	}
+
+}
+
+void DSSaveFileManager::formatSram() {
+	for (int r = 0; r < 65533; r++) {
+		*(CART_RAM + r) = 0;
+	}
+	
+	loadAllFromSRAM();
+}
+
+void DSSaveFileManager::listFiles() {
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid()) {
+			consolePrintf("'%s': %d bytes\n", gbaSave[r].getName(), gbaSave[r].getRamUsage());
+		}
+	}
+	consolePrintf("SRAM free: %d bytes\n", getBytesFree());
+}
+
+DSSaveFileManager* DSSaveFileManager::instancePtr = NULL;
+
+Common::SaveFile *DSSaveFileManager::openSavefile(const char* filename, bool saveOrLoad) {
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) filename))) {
+//			consolePrintf("Matched save %d (%d)\n", r, gbaSave[r].getSize());
+			gbaSave[r].reset();
+			//consolePrintf("reset ");
+			if (saveOrLoad) gbaSave[r].clearData();
+//			consolePrintf("cleared ");
+			return gbaSave[r].clone();
+		}
+	}
+	
+	if (saveOrLoad) {
+		return makeSaveFile(filename, saveOrLoad);
+	} else {
+		return NULL;
+	}
+}
+
+
+
+DSSaveFile* DSSaveFile::clone() {
+//	consolePrintf("Clone %s %d\n", save.name, save.size);
+	return new DSSaveFile(&save, saveCompressed, saveData);
+}
+
+void DSSaveFileManager::deleteFile(char* name) {
+//	consolePrintf("Deleting %s", name);
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) name))) {
+			gbaSave[r].deleteFile();
+		}
+	}
+	flushToSaveRAM();
+}
+
+void DSSaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) {
+	memset(marks, false, num*sizeof(bool));
+
+	for (int saveNum = 0; saveNum < num; saveNum++) {
+		for (int r = 0; r < 8; r++) {
+			if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) prefix, saveNum))) {
+				marks[saveNum] = true;
+			}
+		}
+	}
+	
+}
+
+Common::SaveFile *DSSaveFileManager::makeSaveFile(const char *filename, bool saveOrLoad) {
+	
+	// Find a free save slot
+	int r = 0;
+	
+	while ((r < 8) && (gbaSave[r].isValid())) {
+		r++;
+	}
+	
+	if ((r == 8) && (gbaSave[r].isValid())) {
+		// No more saves
+		return NULL;
+	} else {
+		// Allocate this save
+//		consolePrintf("Allocated save %d\n", r);
+		gbaSave[r].setName((char *) filename);
+		gbaSave[r].reset();
+		return gbaSave[r].clone();
+	}
+}
+
+void DSSaveFileManager::flushToSaveRAM() {
+	int cartAddr = 1;
+	int s;
+	
+	*((u16 *) (0x4000204)) |= 0x3;
+	
+	swiWaitForVBlank();
+
+	int size = 0;
+	for (int r = 0; (r < 8); r++) {
+		if (gbaSave[r].isValid()) {
+			gbaSave[r].compress();
+			if (!gbaSave[r].isTemp()) size += gbaSave[r].getRamUsage();
+		}
+	}
+	
+	if (size <= 65533) {
+
+		for (int r = 0; r < 65533; r++) {
+			*(CART_RAM + r) = 0;
+		}
+		
+		sramBytesFree = 65533;
+		
+		for (int r = 0; (r < 8); r++) {
+			if (gbaSave[r].isValid() && (!gbaSave[r].isTemp())) {
+				
+				cartAddr += s = gbaSave[r].saveToSaveRAM(CART_RAM + cartAddr);
+				
+	/*			if (s == 0) {
+					consolePrintf("WARNING: Save didn't fit in cart RAM and has been lost!!  Delete files and save again.", gbaSave[r].getName());
+					failed = true;
+				}*/
+			}
+		}
+	} else {
+
+		consolePrintf("WARNING: Save didn't fit in cart RAM and has been lost!!  Delete files and save again.");
+		loadAllFromSRAM();
+		
+	}
+//	consolePrintf("SRAM free: %d bytes\n", getBytesFree());
+}
+/* Ramsave
+ * Copyright (C) 2002-2004 Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 
+ */
+ // Save in order 1,2,3,4,larger 2,5
+#include "stdafx.h"
+#include "system.h"
+#include "ramsave.h"
+#include "nds.h"
+#include "compressor/lz.h"
+
+#define CART_RAM ((vu8 *) (0x0A000000))
+
+DSSaveFile::DSSaveFile() {
+	ptr = 0;
+	saveCompressed = false;
+	save.isValid = false;
+	ownsData = false;
+	isOpenFlag = true;
+	isTempFile = false;
+}
+
+DSSaveFile::DSSaveFile(SCUMMSave* s, bool compressed, u8* data) {
+	save = *s;
+	saveData = data;
+	ptr = 0;
+	saveCompressed = compressed;
+	isOpenFlag = true;
+
+	if (saveCompressed) {
+		u8* uncompressed = new unsigned char[save.size];
+		if (!uncompressed) consolePrintf("Out of memory allocating %d!\n", save.size);
+		LZ_Uncompress(saveData, uncompressed, save.compressedSize);
+		saveData = uncompressed;
+		ownsData = true;
+		saveCompressed = false;
+//		consolePrintf("Decompressed. name=%s size=%d (%d)", save.name, save.size, save.compressedSize);
+		
+	} else {
+		ownsData = false;
+		origHeader = s;
+	}
+	
+	if (save.magic == (int) 0xBEEFCAFE) {
+		save.isValid = true;
+	} else {
+		save.isValid = false;
+	}
+	
+	isTempFile = false;
+}
+
+DSSaveFile::~DSSaveFile() {
+	if (!ownsData) {
+		*origHeader = save;
+		DSSaveFileManager::instance()->flushToSaveRAM();
+	}
+	if (ownsData) {
+		delete saveData;
+	}
+}
+
+bool DSSaveFile::loadFromSaveRAM(vu8* address) {
+	
+	SCUMMSave newSave;
+
+	for (int t = 0; t < (int) sizeof(newSave); t++) {
+		((char *) (&newSave))[t] = *(address + t);
+	}
+	
+	
+	if (newSave.magic == 0xBEEFCAFE) {
+		newSave.isValid = true;
+
+		*((u16 *) (0x4000204)) |= 0x3;
+		
+		saveData = new unsigned char[newSave.compressedSize];
+		
+		for (int t = 0; t < (int) newSave.compressedSize; t++) {
+			((char *) (saveData))[t] = *(address + t + sizeof(newSave));
+		}
+		
+		if (ownsData) delete this->saveData;
+		save = newSave;
+		saveCompressed = true;
+		this->saveData = saveData;
+		ownsData = true;
+		ptr = 0;
+		return true;
+	}
+	
+	return false;
+}
+
+void DSSaveFile::compress() {
+	if (!saveCompressed) {
+		unsigned char* compBuffer = new unsigned char[(save.size * 110) / 100];
+		int compSize = LZ_Compress((u8 *) saveData, compBuffer, save.size);
+		save.compressedSize = compSize;
+		
+		
+		
+		delete saveData;
+		
+		// Make the save smaller
+		saveData = (u8 *) realloc(compBuffer, save.compressedSize);
+		saveCompressed = true;
+	}
+}
+
+int DSSaveFile::saveToSaveRAM(vu8* address) {
+
+	unsigned char* compBuffer;
+	bool failed;
+	
+
+	int compSize;
+	
+	compress();
+	
+	compSize = save.compressedSize;
+	compBuffer = saveData;
+	
+	if (DSSaveFileManager::instance()->getBytesFree() >= getRamUsage()) {
+
+		DSSaveFileManager::instance()->addBytesFree(-getRamUsage());
+	
+		// Write header
+		for (int t = 0; t < sizeof(save); t++) {
+			while (*(address + t) != ((char *) (&save))[t]) {
+				*(address + t) = ((char *) (&save))[t];
+			}
+		}
+	
+		// Write compressed buffer
+		for (int t = sizeof(save); t < (int) sizeof(save) + compSize; t++) {
+			while (*(address + t) != compBuffer[t - sizeof(save)]) {
+				*(address + t) = compBuffer[t - sizeof(save)];
+			}
+		}
+		
+		failed = false;
+	} else {
+		failed = true;
+	}
+
+		
+	return failed? 0: compSize + sizeof(save);
+
+}
+
+void DSSaveFile::reset() {
+	ptr = 0;
+}
+
+uint32 DSSaveFile::read(void *buf, uint32 size) {
+	if (ptr + size > save.size) {
+		size = save.size - ptr;
+		if (size < 0) size = 0;
+	}
+	memcpy(buf, saveData + ptr, size);
+//	consolePrintf("byte: %d ", ((u8 *) (buf))[0]);
+	
+	ptr += size;
+	return size;
+}
+
+uint32 DSSaveFile::pos() const {
+	return ptr;
+}
+
+uint32 DSSaveFile::size() const {
+	return save.size;
+}
+
+void DSSaveFile::seek(int32 pos, int whence) {
+	switch (whence) {
+		case SEEK_SET: {
+			ptr = pos;
+			break;
+		}
+		case SEEK_CUR: {
+			ptr += pos;
+			break;
+		}
+		case SEEK_END: {
+			ptr = save.size - pos;
+			break;
+		}
+	}
+}
+
+bool DSSaveFile::eos() const {
+	return ptr >= (int) save.size;
+}
+
+void DSSaveFile::skip(uint32 bytes) {
+	ptr = ptr + bytes;
+	if (ptr > (int) save.size) ptr = save.size;
+}
+
+uint32 DSSaveFile::write(const void *buf, uint32 size) {
+
+	if (ptr + size > DS_MAX_SAVE_SIZE) {
+		size = DS_MAX_SAVE_SIZE - ptr;
+	}
+
+	memcpy(saveData + ptr, buf, size);
+	ptr += size;
+	save.size += size;
+	return size;
+}
+
+bool DSSaveFile::matches(char* prefix, int num) {
+	char str[16];
+	if (isValid()) {
+		sprintf(str, "%s%02d", prefix, num);
+		if (!strcmp(str, save.name)) {
+			return true;
+		} else {
+			return false;
+		}
+	} else {
+		return false;
+	}
+}
+
+bool DSSaveFile::matches(char* filename) {
+	if (isValid()) {
+		return !strcmp(save.name, filename);
+	} else {
+		return false;
+	}
+}
+	
+void DSSaveFile::setName(char *name) {
+	save.isValid = true;
+	save.magic = 0xBEEFCAFE;
+	ownsData = true;
+	save.size = 0;
+	save.compressedSize = 0;
+	saveData = new unsigned char[DS_MAX_SAVE_SIZE];
+	strcpy(save.name, name);
+	
+	if ((strstr(name, ".s99")) || (strstr(name, ".c"))) {
+		isTempFile = true;
+	} else {
+		isTempFile = false;
+	}
+}
+
+void DSSaveFile::clearData() {
+	save.size = 0;
+
+	if (saveCompressed) {
+		if (ownsData) {
+			delete saveData;
+			DSSaveFileManager::instance()->addBytesFree(getRamUsage());
+		}
+		saveData = new unsigned char[DS_MAX_SAVE_SIZE];
+		saveCompressed = false;
+		ownsData = true;
+	}
+
+}
+
+void DSSaveFile::deleteFile() {
+	if (isValid()) {
+		if (ownsData) {
+			DSSaveFileManager::instance()->addBytesFree(getRamUsage());
+			delete saveData;
+			saveData = NULL;
+		}
+		ptr = 0;
+		saveCompressed = false;
+		save.isValid = false;
+		ownsData = false;
+		isOpenFlag = true;
+	}
+}
+
+DSSaveFileManager::DSSaveFileManager() {
+	instancePtr = this;
+	
+	*((u16 *) (0x4000204)) |= 0x3;
+	swiWaitForVBlank();
+	
+	loadAllFromSRAM();
+}
+
+DSSaveFileManager::~DSSaveFileManager() {
+	instancePtr = NULL;
+}
+
+void DSSaveFileManager::loadAllFromSRAM() {
+	int addr = 1;
+	
+	for (int r = 0; r < 8; r++) {
+		gbaSave[r].deleteFile();
+	}
+
+	sramBytesFree = 65533;
+
+	// Try to find saves in save RAM
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].loadFromSaveRAM(CART_RAM + addr)) {
+			addr += gbaSave[r].getRamUsage();
+			sramBytesFree -= gbaSave[r].getRamUsage();
+		}
+	}
+
+}
+
+void DSSaveFileManager::formatSram() {
+	for (int r = 0; r < 65533; r++) {
+		*(CART_RAM + r) = 0;
+	}
+	
+	loadAllFromSRAM();
+}
+
+void DSSaveFileManager::listFiles() {
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid()) {
+			consolePrintf("'%s': %d bytes\n", gbaSave[r].getName(), gbaSave[r].getRamUsage());
+		}
+	}
+	consolePrintf("SRAM free: %d bytes\n", getBytesFree());
+}
+
+DSSaveFileManager* DSSaveFileManager::instancePtr = NULL;
+
+Common::SaveFile *DSSaveFileManager::openSavefile(const char* filename, bool saveOrLoad) {
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) filename))) {
+//			consolePrintf("Matched save %d (%d)\n", r, gbaSave[r].getSize());
+			gbaSave[r].reset();
+			//consolePrintf("reset ");
+			if (saveOrLoad) gbaSave[r].clearData();
+//			consolePrintf("cleared ");
+			return gbaSave[r].clone();
+		}
+	}
+	
+	if (saveOrLoad) {
+		return makeSaveFile(filename, saveOrLoad);
+	} else {
+		return NULL;
+	}
+}
+
+
+
+DSSaveFile* DSSaveFile::clone() {
+//	consolePrintf("Clone %s %d\n", save.name, save.size);
+	return new DSSaveFile(&save, saveCompressed, saveData);
+}
+
+void DSSaveFileManager::deleteFile(char* name) {
+//	consolePrintf("Deleting %s", name);
+	for (int r = 0; r < 8; r++) {
+		if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) name))) {
+			gbaSave[r].deleteFile();
+		}
+	}
+	flushToSaveRAM();
+}
+
+void DSSaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) {
+	memset(marks, false, num*sizeof(bool));
+
+	for (int saveNum = 0; saveNum < num; saveNum++) {
+		for (int r = 0; r < 8; r++) {
+			if (gbaSave[r].isValid() && (gbaSave[r].matches((char *) prefix, saveNum))) {
+				marks[saveNum] = true;
+			}
+		}
+	}
+	
+}
+
+Common::SaveFile *DSSaveFileManager::makeSaveFile(const char *filename, bool saveOrLoad) {
+	
+	// Find a free save slot
+	int r = 0;
+	
+	while ((r < 8) && (gbaSave[r].isValid())) {
+		r++;
+	}
+	
+	if ((r == 8) && (gbaSave[r].isValid())) {
+		// No more saves
+		return NULL;
+	} else {
+		// Allocate this save
+//		consolePrintf("Allocated save %d\n", r);
+		gbaSave[r].setName((char *) filename);
+		gbaSave[r].reset();
+		return gbaSave[r].clone();
+	}
+}
+
+void DSSaveFileManager::flushToSaveRAM() {
+	int cartAddr = 1;
+	int s;
+	
+	*((u16 *) (0x4000204)) |= 0x3;
+	
+	swiWaitForVBlank();
+
+	int size = 0;
+	for (int r = 0; (r < 8); r++) {
+		if (gbaSave[r].isValid()) {
+			gbaSave[r].compress();
+			if (!gbaSave[r].isTemp()) size += gbaSave[r].getRamUsage();
+		}
+	}
+	
+	if (size <= 65533) {
+
+		for (int r = 0; r < 65533; r++) {
+			*(CART_RAM + r) = 0;
+		}
+		
+		sramBytesFree = 65533;
+		
+		for (int r = 0; (r < 8); r++) {
+			if (gbaSave[r].isValid() && (!gbaSave[r].isTemp())) {
+				
+				cartAddr += s = gbaSave[r].saveToSaveRAM(CART_RAM + cartAddr);
+				
+	/*			if (s == 0) {
+					consolePrintf("WARNING: Save didn't fit in cart RAM and has been lost!!  Delete files and save again.", gbaSave[r].getName());
+					failed = true;
+				}*/
+			}
+		}
+	} else {
+
+		consolePrintf("WARNING: Save didn't fit in cart RAM and has been lost!!  Delete files and save again.");
+		loadAllFromSRAM();
+		
+	}
+//	consolePrintf("SRAM free: %d bytes\n", getBytesFree());
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/ramsave.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/ramsave.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/ramsave.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/ramsave.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,280 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _RAMSAVE_H_
+#define _RAMSAVE_H_
+
+#include "system.h"
+#include "savefile.h"
+
+// SaveFileManager class
+
+#define DS_MAX_SAVE_SIZE 150000
+
+class DSSaveFile : public Common::SaveFile {
+	int address;
+	int ptr;
+	bool ownsData;
+	bool saveCompressed;
+
+	struct SCUMMSave {
+		u32 magic;
+		bool isValid;
+		bool pad;
+		char name[16];
+		u32 size;
+		u32 compressedSize;
+		u16 pad2;
+		u32 reserved;
+	} __attribute__ ((packed));
+	
+	SCUMMSave save;
+	u8* saveData;
+	SCUMMSave* origHeader;
+	bool isOpenFlag;
+	bool isTempFile;
+	
+public:
+	DSSaveFile();
+	DSSaveFile(SCUMMSave* s, bool saveCompressed, u8* data);
+	~DSSaveFile();
+	
+	void reset();
+	
+	bool isOpen() const { return isOpenFlag; }
+	virtual bool eos() const;
+	virtual void skip(uint32 size);
+	
+	virtual uint32 pos() const;
+	virtual uint32 size() const;
+	virtual void seek(int32 pos, int whence);
+
+	uint32 read(void *buf, uint32 size);
+	uint32 write(const void *buf, uint32 size);
+	
+	void setName(char *name);
+	char* getName() { return save.name; }
+	
+	bool isValid() { return save.isValid; }
+	bool isTemp() { return isTempFile; }
+	bool matches(char* prefix, int num);
+	bool matches(char* filename);
+	
+	void clearData();
+	void compress();
+	
+	int getRamUsage() { return sizeof(save) + save.compressedSize; }
+	char* getRamImage() { return (char *) &save; }
+	
+	int getSize() { return save.size; }
+	
+	DSSaveFile* clone();
+	
+	bool loadFromSaveRAM(vu8* address);
+	int saveToSaveRAM(vu8* address);
+	
+	
+	void deleteFile();
+	
+	void operator delete(void *p) {
+//		consolePrintf("Finished! size=%d\n", ((DSSaveFile *) (p))->save->size);
+	}
+
+
+
+};
+
+
+
+class DSSaveFileManager : public Common::SaveFileManager {
+	
+	DSSaveFile gbaSave[8];
+	static DSSaveFileManager* instancePtr;
+	int sramBytesFree;
+	
+public:
+	DSSaveFileManager();
+	~DSSaveFileManager();
+	
+	static DSSaveFileManager* instance() { return instancePtr; }
+
+	Common::SaveFile *openSavefile(const char *filename, bool saveOrLoad);
+	
+	virtual Common::OutSaveFile* openForSaving(const char* filename) { return openSavefile(filename, true); }
+	virtual Common::InSaveFile* openForLoading(const char* filename) { return openSavefile(filename, false); }
+	
+	
+	void listSavefiles(const char *prefix, bool *marks, int num);
+	
+	void flushToSaveRAM();
+	
+	void addBytesFree(int size) { sramBytesFree += size; }
+	int getBytesFree() { return sramBytesFree; }
+
+	void deleteFile(char* name);
+	void listFiles();
+	void formatSram();
+	
+	void loadAllFromSRAM();
+
+protected:
+	Common::SaveFile *makeSaveFile(const char *filename, bool saveOrLoad);
+};
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _RAMSAVE_H_
+#define _RAMSAVE_H_
+
+#include "system.h"
+#include "savefile.h"
+
+// SaveFileManager class
+
+#define DS_MAX_SAVE_SIZE 150000
+
+class DSSaveFile : public Common::SaveFile {
+	int address;
+	int ptr;
+	bool ownsData;
+	bool saveCompressed;
+
+	struct SCUMMSave {
+		u32 magic;
+		bool isValid;
+		bool pad;
+		char name[16];
+		u32 size;
+		u32 compressedSize;
+		u16 pad2;
+		u32 reserved;
+	} __attribute__ ((packed));
+	
+	SCUMMSave save;
+	u8* saveData;
+	SCUMMSave* origHeader;
+	bool isOpenFlag;
+	bool isTempFile;
+	
+public:
+	DSSaveFile();
+	DSSaveFile(SCUMMSave* s, bool saveCompressed, u8* data);
+	~DSSaveFile();
+	
+	void reset();
+	
+	bool isOpen() const { return isOpenFlag; }
+	virtual bool eos() const;
+	virtual void skip(uint32 size);
+	
+	virtual uint32 pos() const;
+	virtual uint32 size() const;
+	virtual void seek(int32 pos, int whence);
+
+	uint32 read(void *buf, uint32 size);
+	uint32 write(const void *buf, uint32 size);
+	
+	void setName(char *name);
+	char* getName() { return save.name; }
+	
+	bool isValid() { return save.isValid; }
+	bool isTemp() { return isTempFile; }
+	bool matches(char* prefix, int num);
+	bool matches(char* filename);
+	
+	void clearData();
+	void compress();
+	
+	int getRamUsage() { return sizeof(save) + save.compressedSize; }
+	char* getRamImage() { return (char *) &save; }
+	
+	int getSize() { return save.size; }
+	
+	DSSaveFile* clone();
+	
+	bool loadFromSaveRAM(vu8* address);
+	int saveToSaveRAM(vu8* address);
+	
+	
+	void deleteFile();
+	
+	void operator delete(void *p) {
+//		consolePrintf("Finished! size=%d\n", ((DSSaveFile *) (p))->save->size);
+	}
+
+
+
+};
+
+
+
+class DSSaveFileManager : public Common::SaveFileManager {
+	
+	DSSaveFile gbaSave[8];
+	static DSSaveFileManager* instancePtr;
+	int sramBytesFree;
+	
+public:
+	DSSaveFileManager();
+	~DSSaveFileManager();
+	
+	static DSSaveFileManager* instance() { return instancePtr; }
+
+	Common::SaveFile *openSavefile(const char *filename, bool saveOrLoad);
+	
+	virtual Common::OutSaveFile* openForSaving(const char* filename) { return openSavefile(filename, true); }
+	virtual Common::InSaveFile* openForLoading(const char* filename) { return openSavefile(filename, false); }
+	
+	
+	void listSavefiles(const char *prefix, bool *marks, int num);
+	
+	void flushToSaveRAM();
+	
+	void addBytesFree(int size) { sramBytesFree += size; }
+	int getBytesFree() { return sramBytesFree; }
+
+	void deleteFile(char* name);
+	void listFiles();
+	void formatSram();
+	
+	void loadAllFromSRAM();
+
+protected:
+	Common::SaveFile *makeSaveFile(const char *filename, bool saveOrLoad);
+};
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/ramsave.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.c
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.c	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.c	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,1122 @@
+//////////////////////////////////////////////////////////////////////
+//
+// console.cpp -- provides basic print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include <NDS.h>
+#include "scummconsole.h"
+
+#include <stdarg.h>
+
+#include <default_font_bin.h>
+
+/////////////////////////////////////////
+//global console variables
+
+#define CONSOLE_WIDTH 32
+#define CONSOLE_HEIGHT 24
+#define TAB_SIZE 3
+
+//map to print to
+u16* fontMap;
+
+//location of cursor
+u8 row, col;
+
+//font may not start on a character base boundry
+u16 fontOffset; 
+
+//the first character in the set (0 if you have a full set)
+u16 fontStart;
+
+//the 16-color palette to use
+u16 fontPal;
+
+
+
+
+///////////////////////////////////////////////////////////
+//consoleInit
+// param: 
+//		font: 16 color font
+//		charBase: the location the font data will be loaded to
+//		numCharacters: count of characters in the font
+//		charStart: The ascii number of the first character in the font set
+//					if you have a full set this will be zero
+//		map: pointer to the map you will be printing to.
+//		pal: specifies the 16 color palette to use, if > 15 it will change all non-zero
+//			entries in the font to use palette index 255
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth)
+{
+	int i;
+
+	row = col = 0;
+	
+	fontStart = charStart;
+
+	fontOffset = 0;
+
+	fontMap = map;
+
+	if(bitDepth == 16)
+	{
+		if(pal < 16)
+		{
+			fontPal = pal << 12;
+
+			for (i = 0; i < numCharacters * 16; i++)
+				charBase[i] = font[i];
+		}
+		else
+		{
+			fontPal = 15 << 12;
+
+			for (i = 0; i < numCharacters * 16; i++)
+			{
+				u16 temp = 0;
+
+				if(font[i] & 0xF)
+					temp |= 0xF;
+				if(font[i] & 0xF0)
+					temp |= 0xF0;
+				if(font[i] & 0xF00)
+					temp |= 0xF00;
+				if(font[i] & 0xF000)
+					temp |= 0xF000;
+	
+				charBase[i] = temp;
+			}	
+		}
+	}//end if bitdepth
+	else
+	{
+		fontPal = 0;
+		for(i = 0; i < numCharacters * 16; i++)
+		{
+			u32 temp = 0;
+
+			if(font[i] & 0xF)
+				temp = 255;
+			if(font[i] & 0xF0)
+				temp |= 255 << 8;
+			if(font[i] & 0xF00)
+				temp |= 255 << 16;
+			if(font[i] & 0xF000)
+				temp |= 255 << 24;
+
+			((u32*)charBase)[i] = temp;
+
+		}
+	}
+}
+
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth)
+{
+	consoleInit((u16 *) default_font_bin, charBase, 256, 0, map, CONSOLE_USE_COLOR255, bitDepth); 	
+}
+
+void consolePrintSet(int x, int y)
+{
+	if(y < CONSOLE_HEIGHT)
+		row = y;
+	else
+		row = CONSOLE_HEIGHT - 1;
+
+	if(x < CONSOLE_WIDTH)
+		col = x;
+	else
+		col = CONSOLE_WIDTH - 1;
+}
+
+void consolePrintChar(char c)
+{
+	int i;
+
+	if(col >= CONSOLE_WIDTH)
+	{
+		col = 0;
+
+		row++;		
+	}
+	
+	if(row >= CONSOLE_HEIGHT)
+	{
+		row--;
+
+		for(i = CONSOLE_WIDTH; i < CONSOLE_HEIGHT * CONSOLE_WIDTH; i++)
+			fontMap[i - CONSOLE_WIDTH] = fontMap[i];
+		for(i = 0; i < CONSOLE_WIDTH; i++)
+			fontMap[i + (CONSOLE_HEIGHT-1)*CONSOLE_WIDTH] = fontPal | (u16)(' ' + fontOffset - fontStart);
+
+
+	}
+	
+	switch(c)
+	{
+
+	case 10:
+	case 11:
+	case 12:
+	case 13:
+		row++;
+		col = 0;
+		break;
+	case 9:
+		col += TAB_SIZE;
+		break;
+	default:
+		fontMap[col + row * CONSOLE_WIDTH] = fontPal | (u16)(c + fontOffset - fontStart);
+		col++;
+		break;
+
+	}
+
+	
+}
+
+
+void printX(int w, unsigned d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0};
+
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'A' - 10);
+		}
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printx(int w, unsigned int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0};
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'a' - 10);
+		}
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printInt(int w, int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0}; 
+
+	if(d < 0)
+	{
+		consolePrintChar('-');
+		d *= -1;
+	}
+
+	if (d == 0)
+		buf[loop++] = 0;
+	else while (d > 0)
+	{
+		buf[loop++] =  d % 10;
+		d /= 10; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+			consolePrintChar(buf[i] + '0');
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printBin(int w, int d)
+{
+	int i;
+	int first = 0;
+	for (i = 31; i >= 0; i--)
+	{
+		if(d & BIT(i))
+		{
+			first = 1;
+			consolePrintChar('1');
+		}
+		else if (first  || i == 0)
+			consolePrintChar('0');
+		else if (i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void print0X(int w, unsigned d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < w  || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'A' - 10);
+		}
+	}
+}
+
+void print0x(int w, unsigned int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < w  || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'a' - 10);
+		}
+	}
+}
+
+void print0Int(int w, int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+	if(d < 0)
+	{
+		consolePrintChar('-');
+		d *= -1;
+	}
+
+	while(d > 0)
+	{
+		buf[loop++] =  d % 10;
+		d /= 10;  
+	}
+	
+	for (i = 15; i >= 0; i--)
+		if(buf[i] || i < w  || i < loop)
+			consolePrintChar(buf[i] + '0');
+
+}
+
+void print0Bin(int w, int d)
+{
+	int i;
+	int first = 0;
+	for (i = 31; i >= 0; i--)
+	{
+		if(d & BIT(i))
+		{
+			first = 1;
+			consolePrintChar('1');
+		}
+		else if (first  || i == 0)
+			consolePrintChar('0');
+		else if (i < w)
+			consolePrintChar('0');
+	}
+}
+
+void print(const char* s)
+{
+	for(; *s; s++) consolePrintChar(*s);
+}
+
+void printF(int w, float f)
+{
+	unsigned int* t = (unsigned int*)&f;
+	unsigned int fraction = (*t) & 0x007FFFFF;
+	int exp = ((*t) >> 23) & 0xFF;
+
+	if(*t & BIT(31))
+		consolePrintChar('-');
+	
+
+	print0Bin(32, fraction);
+	
+	printInt(1, fraction);
+	consolePrintChar('e');
+	printInt(1, exp - 127);
+	
+	/*
+	if(exp == 0 && fraction == 0)
+	{
+		printInt(1,0);
+	}
+	else if(exp == 0xFF && fraction == 0)
+	{
+		print("Inifinite");
+	}
+	else
+	{
+		printInt(w,fraction);
+		consolePrintChar('e');
+		printInt(1,exp - 127);
+	}
+	*/
+}
+
+void consolePrintf(const char* s, ...)
+{
+	int w = 1, z = 0;
+
+	va_list argp;
+
+	va_start(argp, s);
+	
+
+	while(*s)
+	{
+		w = 1;
+		z = 0;
+
+		switch(*s)
+		{
+		case '%':
+			s++;
+			if(*s == '0')
+			{
+				z = 1;
+				s++;
+			}
+			if(*s > '0' && *s <= '9')
+			{
+				w = *s - '0';
+				s++;
+			}
+			switch (*s)
+			{
+			case 'i':
+			case 'I':
+			case 'd':
+			case 'D':
+				if(z)print0Int(w, va_arg(argp, int)); 
+				else printInt(w, va_arg(argp, int));
+				s++;
+				break;
+			case 'X':
+				if(z)print0X(w, va_arg(argp, int));
+				else printX(w, va_arg(argp, int));
+				s++;
+				break;
+
+			case 'x':
+				if(z)print0x(w, va_arg(argp, int));
+				else printx(w, va_arg(argp, int));
+				s++;
+				break;
+
+			case 'b':
+			case 'B':
+				if(z)print0Bin(w, va_arg(argp, int));
+				else printBin(w, va_arg(argp, int));
+				s++;
+				break;
+			case 'f':
+			case 'F':
+				printF(w,va_arg(argp, double));
+				s++;
+				break;
+			case 's':
+			case 'S':
+				print(va_arg(argp, char*));
+				s++;
+				break;
+			default:
+				consolePrintChar('%');
+				break;
+			}
+		default:
+			consolePrintChar(*s);
+			break;
+		}
+
+		s++;
+	}
+	va_end(argp);
+}
+
+void consolePutString(int x, int y, char* s)
+{
+	consolePrintSet(x, y);
+	consolePrintf(s);
+}
+
+void consolePutInt(int x, int y, int d)
+{
+	consolePrintSet(x,y);
+	printInt(1,d);
+}
+
+void consolePutX(int x, int y, int d)
+{
+	consolePrintSet(x, y);
+	printX(1,d);
+}
+
+void consolePutChar(int x, int y, char c)
+{
+	consolePrintSet(x, y);
+	consolePrintChar(c);
+}
+
+void consolePutBin(int x, int y, int b)
+{
+	consolePrintSet(x, y);
+	printBin(1,b);
+}
+void consoleClear(void)
+{
+	int i = 0;
+	consolePrintSet(0,0);
+
+	while(i++ < CONSOLE_HEIGHT * CONSOLE_WIDTH)
+		consolePrintChar(' ');
+
+	consolePrintSet(0,0);
+}
+//////////////////////////////////////////////////////////////////////
+//
+// console.cpp -- provides basic print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include <NDS.h>
+#include "scummconsole.h"
+
+#include <stdarg.h>
+
+#include <default_font_bin.h>
+
+/////////////////////////////////////////
+//global console variables
+
+#define CONSOLE_WIDTH 32
+#define CONSOLE_HEIGHT 24
+#define TAB_SIZE 3
+
+//map to print to
+u16* fontMap;
+
+//location of cursor
+u8 row, col;
+
+//font may not start on a character base boundry
+u16 fontOffset; 
+
+//the first character in the set (0 if you have a full set)
+u16 fontStart;
+
+//the 16-color palette to use
+u16 fontPal;
+
+
+
+
+///////////////////////////////////////////////////////////
+//consoleInit
+// param: 
+//		font: 16 color font
+//		charBase: the location the font data will be loaded to
+//		numCharacters: count of characters in the font
+//		charStart: The ascii number of the first character in the font set
+//					if you have a full set this will be zero
+//		map: pointer to the map you will be printing to.
+//		pal: specifies the 16 color palette to use, if > 15 it will change all non-zero
+//			entries in the font to use palette index 255
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth)
+{
+	int i;
+
+	row = col = 0;
+	
+	fontStart = charStart;
+
+	fontOffset = 0;
+
+	fontMap = map;
+
+	if(bitDepth == 16)
+	{
+		if(pal < 16)
+		{
+			fontPal = pal << 12;
+
+			for (i = 0; i < numCharacters * 16; i++)
+				charBase[i] = font[i];
+		}
+		else
+		{
+			fontPal = 15 << 12;
+
+			for (i = 0; i < numCharacters * 16; i++)
+			{
+				u16 temp = 0;
+
+				if(font[i] & 0xF)
+					temp |= 0xF;
+				if(font[i] & 0xF0)
+					temp |= 0xF0;
+				if(font[i] & 0xF00)
+					temp |= 0xF00;
+				if(font[i] & 0xF000)
+					temp |= 0xF000;
+	
+				charBase[i] = temp;
+			}	
+		}
+	}//end if bitdepth
+	else
+	{
+		fontPal = 0;
+		for(i = 0; i < numCharacters * 16; i++)
+		{
+			u32 temp = 0;
+
+			if(font[i] & 0xF)
+				temp = 255;
+			if(font[i] & 0xF0)
+				temp |= 255 << 8;
+			if(font[i] & 0xF00)
+				temp |= 255 << 16;
+			if(font[i] & 0xF000)
+				temp |= 255 << 24;
+
+			((u32*)charBase)[i] = temp;
+
+		}
+	}
+}
+
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth)
+{
+	consoleInit((u16 *) default_font_bin, charBase, 256, 0, map, CONSOLE_USE_COLOR255, bitDepth); 	
+}
+
+void consolePrintSet(int x, int y)
+{
+	if(y < CONSOLE_HEIGHT)
+		row = y;
+	else
+		row = CONSOLE_HEIGHT - 1;
+
+	if(x < CONSOLE_WIDTH)
+		col = x;
+	else
+		col = CONSOLE_WIDTH - 1;
+}
+
+void consolePrintChar(char c)
+{
+	int i;
+
+	if(col >= CONSOLE_WIDTH)
+	{
+		col = 0;
+
+		row++;		
+	}
+	
+	if(row >= CONSOLE_HEIGHT)
+	{
+		row--;
+
+		for(i = CONSOLE_WIDTH; i < CONSOLE_HEIGHT * CONSOLE_WIDTH; i++)
+			fontMap[i - CONSOLE_WIDTH] = fontMap[i];
+		for(i = 0; i < CONSOLE_WIDTH; i++)
+			fontMap[i + (CONSOLE_HEIGHT-1)*CONSOLE_WIDTH] = fontPal | (u16)(' ' + fontOffset - fontStart);
+
+
+	}
+	
+	switch(c)
+	{
+
+	case 10:
+	case 11:
+	case 12:
+	case 13:
+		row++;
+		col = 0;
+		break;
+	case 9:
+		col += TAB_SIZE;
+		break;
+	default:
+		fontMap[col + row * CONSOLE_WIDTH] = fontPal | (u16)(c + fontOffset - fontStart);
+		col++;
+		break;
+
+	}
+
+	
+}
+
+
+void printX(int w, unsigned d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0};
+
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'A' - 10);
+		}
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printx(int w, unsigned int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0};
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'a' - 10);
+		}
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printInt(int w, int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[20] = {0}; 
+
+	if(d < 0)
+	{
+		consolePrintChar('-');
+		d *= -1;
+	}
+
+	if (d == 0)
+		buf[loop++] = 0;
+	else while (d > 0)
+	{
+		buf[loop++] =  d % 10;
+		d /= 10; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < loop)
+			consolePrintChar(buf[i] + '0');
+		else if(i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void printBin(int w, int d)
+{
+	int i;
+	int first = 0;
+	for (i = 31; i >= 0; i--)
+	{
+		if(d & BIT(i))
+		{
+			first = 1;
+			consolePrintChar('1');
+		}
+		else if (first  || i == 0)
+			consolePrintChar('0');
+		else if (i < w)
+			consolePrintChar(' ');
+	}
+}
+
+void print0X(int w, unsigned d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < w  || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'A' - 10);
+		}
+	}
+}
+
+void print0x(int w, unsigned int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+
+	while(d > 0)
+	{
+		buf[loop++] =  d & 0xF;
+		d = d>>4; 
+	}
+	
+	for (i = 7; i >= 0; i--)
+	{
+		if(buf[i] || i < w  || i < loop)
+		{
+			if(buf[i] < 10)
+				consolePrintChar(buf[i] + '0');
+			else
+				consolePrintChar(buf[i] + 'a' - 10);
+		}
+	}
+}
+
+void print0Int(int w, int d)
+{
+	int loop = 0;
+	int i = 0;
+	
+	char buf[] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; //set to zero cause I may add formatted output someday
+	
+	if(d < 0)
+	{
+		consolePrintChar('-');
+		d *= -1;
+	}
+
+	while(d > 0)
+	{
+		buf[loop++] =  d % 10;
+		d /= 10;  
+	}
+	
+	for (i = 15; i >= 0; i--)
+		if(buf[i] || i < w  || i < loop)
+			consolePrintChar(buf[i] + '0');
+
+}
+
+void print0Bin(int w, int d)
+{
+	int i;
+	int first = 0;
+	for (i = 31; i >= 0; i--)
+	{
+		if(d & BIT(i))
+		{
+			first = 1;
+			consolePrintChar('1');
+		}
+		else if (first  || i == 0)
+			consolePrintChar('0');
+		else if (i < w)
+			consolePrintChar('0');
+	}
+}
+
+void print(const char* s)
+{
+	for(; *s; s++) consolePrintChar(*s);
+}
+
+void printF(int w, float f)
+{
+	unsigned int* t = (unsigned int*)&f;
+	unsigned int fraction = (*t) & 0x007FFFFF;
+	int exp = ((*t) >> 23) & 0xFF;
+
+	if(*t & BIT(31))
+		consolePrintChar('-');
+	
+
+	print0Bin(32, fraction);
+	
+	printInt(1, fraction);
+	consolePrintChar('e');
+	printInt(1, exp - 127);
+	
+	/*
+	if(exp == 0 && fraction == 0)
+	{
+		printInt(1,0);
+	}
+	else if(exp == 0xFF && fraction == 0)
+	{
+		print("Inifinite");
+	}
+	else
+	{
+		printInt(w,fraction);
+		consolePrintChar('e');
+		printInt(1,exp - 127);
+	}
+	*/
+}
+
+void consolePrintf(const char* s, ...)
+{
+	int w = 1, z = 0;
+
+	va_list argp;
+
+	va_start(argp, s);
+	
+
+	while(*s)
+	{
+		w = 1;
+		z = 0;
+
+		switch(*s)
+		{
+		case '%':
+			s++;
+			if(*s == '0')
+			{
+				z = 1;
+				s++;
+			}
+			if(*s > '0' && *s <= '9')
+			{
+				w = *s - '0';
+				s++;
+			}
+			switch (*s)
+			{
+			case 'i':
+			case 'I':
+			case 'd':
+			case 'D':
+				if(z)print0Int(w, va_arg(argp, int)); 
+				else printInt(w, va_arg(argp, int));
+				s++;
+				break;
+			case 'X':
+				if(z)print0X(w, va_arg(argp, int));
+				else printX(w, va_arg(argp, int));
+				s++;
+				break;
+
+			case 'x':
+				if(z)print0x(w, va_arg(argp, int));
+				else printx(w, va_arg(argp, int));
+				s++;
+				break;
+
+			case 'b':
+			case 'B':
+				if(z)print0Bin(w, va_arg(argp, int));
+				else printBin(w, va_arg(argp, int));
+				s++;
+				break;
+			case 'f':
+			case 'F':
+				printF(w,va_arg(argp, double));
+				s++;
+				break;
+			case 's':
+			case 'S':
+				print(va_arg(argp, char*));
+				s++;
+				break;
+			default:
+				consolePrintChar('%');
+				break;
+			}
+		default:
+			consolePrintChar(*s);
+			break;
+		}
+
+		s++;
+	}
+	va_end(argp);
+}
+
+void consolePutString(int x, int y, char* s)
+{
+	consolePrintSet(x, y);
+	consolePrintf(s);
+}
+
+void consolePutInt(int x, int y, int d)
+{
+	consolePrintSet(x,y);
+	printInt(1,d);
+}
+
+void consolePutX(int x, int y, int d)
+{
+	consolePrintSet(x, y);
+	printX(1,d);
+}
+
+void consolePutChar(int x, int y, char c)
+{
+	consolePrintSet(x, y);
+	consolePrintChar(c);
+}
+
+void consolePutBin(int x, int y, int b)
+{
+	consolePrintSet(x, y);
+	printBin(1,b);
+}
+void consoleClear(void)
+{
+	int i = 0;
+	consolePrintSet(0,0);
+
+	while(i++ < CONSOLE_HEIGHT * CONSOLE_WIDTH)
+		consolePrintChar(' ');
+
+	consolePrintSet(0,0);
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,124 @@
+//////////////////////////////////////////////////////////////////////
+//
+// consol.h --provides basic consol type print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+#ifndef CONSOLE_H2
+#define CONSOLE_H2
+
+#define CONSOLE_USE_COLOR255 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth);
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth);
+
+void consolePrintf(const char* s, ...);
+
+void consolePrintSet(int x, int y);
+
+void consolePrintChar(char c);
+
+void consolePutString(int x, int y, char* s);
+void consolePutInt(int x, int y, int d);
+void consolePutX(int x, int y, int d);
+void consolePutChar(int x, int y, char c);
+void consolePutBin(int x, int y, int b);
+
+void consoleClear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+//////////////////////////////////////////////////////////////////////
+//
+// consol.h --provides basic consol type print functionality
+//
+// version 0.1, February 14, 2005
+//
+//  Copyright (C) 2005 Michael Noland (joat) and Jason Rogers (dovoto)
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any
+//  damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any
+//  purpose, including commercial applications, and to alter it and
+//  redistribute it freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you
+//     must not claim that you wrote the original software. If you use
+//     this software in a product, an acknowledgment in the product
+//     documentation would be appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and
+//     must not be misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source
+//     distribution.
+//
+// Changelog:
+//   0.1: First version
+//	 0.2: Fixed sprite mapping bug.  1D mapping should work now.  
+//			Changed some register defines for consistency.
+//
+//////////////////////////////////////////////////////////////////////
+#ifndef CONSOLE_H2
+#define CONSOLE_H2
+
+#define CONSOLE_USE_COLOR255 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void consoleInit(u16* font, u16* charBase, u16 numCharacters, u8 charStart, u16* map, u8 pal, u8 bitDepth);
+void consoleInitDefault(u16* map, u16* charBase, u8 bitDepth);
+
+void consolePrintf(const char* s, ...);
+
+void consolePrintSet(int x, int y);
+
+void consolePrintChar(char c);
+
+void consolePutString(int x, int y, char* s);
+void consolePutInt(int x, int y, int d);
+void consolePutX(int x, int y, int d);
+void consolePutChar(int x, int y, char c);
+void consolePutBin(int x, int y, int b);
+
+void consoleClear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/scummconsole.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,172 @@
+#include "stdafx.h"
+#include "scummhelp.h"
+
+#define ADD_BIND(k,d) do { key[i] = k; dsc[i] = d; i++; } while (0)
+#define ADD_TEXT(d) ADD_BIND("",d)
+#define ADD_LINE ADD_BIND("","")
+
+#define HELP_NUM_LINES 15
+
+namespace DS {
+
+void updateStrings(byte gameId, byte version, Common::Platform platform,
+			int page, Common::String &title, Common::String *&key, Common::String *&dsc) {
+	key = new Common::String[HELP_NUM_LINES];
+	dsc = new Common::String[HELP_NUM_LINES];
+	int i = 0;
+	switch (page) {
+	case 1: {
+		title = "DS Controls (right handed):";
+		ADD_BIND("Pad Left", "Left mouse button");
+		ADD_BIND("Pad Right", "Right mouse button");
+		ADD_BIND("Pad Up", "Mouse hover mode (no click)");
+		ADD_BIND("Pad Down", "Skip dialog line (some games)");
+		ADD_BIND("Start", "Pause/Game menu");
+		ADD_BIND("Select", "DS Options menu");
+		ADD_BIND("B", "Skip cutscenes");
+		ADD_BIND("A", "Switch screens");
+		ADD_BIND("Y", "Show/hide debug console");
+		ADD_BIND("X", "Show/hide keyboard");
+		ADD_BIND("L + Pad", "Scroll current touch screen view");
+		ADD_BIND("L + Pen", "Scroll current touch screen view");
+		ADD_BIND("L + B", "Zoom in");
+		ADD_BIND("L + A", "Zoom out");
+		break;
+	}
+
+	case 2: {
+		title = "DS Controls (left handed):";
+		ADD_BIND("Y", "Left mouse button");
+		ADD_BIND("A", "Right mouse button");
+		ADD_BIND("X", "Mouse hover mode (no click)");
+		ADD_BIND("B", "Skip dialog line (some games)");
+		ADD_BIND("Start", "Pause/Game menu");
+		ADD_BIND("Select", "DS Options menu");
+		ADD_BIND("Pad Down", "Skip cutscenes");
+		ADD_BIND("Pad Up", "Show/hide keyboard");
+		ADD_BIND("Pad Left", "Show/hide debug console");
+		ADD_BIND("Pad Right", "Swap screens");
+		ADD_BIND("R + Pad", "Scroll current touch screen view");
+		ADD_BIND("R + Pen", "Scroll current touch screen view");
+		ADD_BIND("R + B", "Zoom in");
+		ADD_BIND("R + A", "Zoom out");
+		break;
+	}
+
+	case 3: {
+		title = "Indiana Jones Fighting controls:";
+		ADD_BIND("Pad Left", "Move left");
+		ADD_BIND("Pad Right", "Move right");
+		ADD_BIND("Pad Up", "High guard");
+		ADD_BIND("Pad Down", "Guard down");
+		ADD_BIND("Y", "Guard middle");
+		ADD_BIND("X", "Punch high");
+		ADD_BIND("A", "Punch middle");
+		ADD_BIND("B", "Punch low");
+
+		ADD_BIND("L+R", "Hold during bootup to clear SRAM");
+		ADD_BIND("", "(flash cart only)");
+		break;
+	}
+	}
+
+
+	while (i < HELP_NUM_LINES) {
+		ADD_LINE;
+	}
+
+}
+
+}
+
+
+#undef ADD_BIND
+#undef ADD_TEXT
+#undef ADD_LINE
+
+#include "stdafx.h"
+#include "scummhelp.h"
+
+#define ADD_BIND(k,d) do { key[i] = k; dsc[i] = d; i++; } while (0)
+#define ADD_TEXT(d) ADD_BIND("",d)
+#define ADD_LINE ADD_BIND("","")
+
+#define HELP_NUM_LINES 15
+
+namespace DS {
+
+void updateStrings(byte gameId, byte version, Common::Platform platform,
+			int page, Common::String &title, Common::String *&key, Common::String *&dsc) {
+	key = new Common::String[HELP_NUM_LINES];
+	dsc = new Common::String[HELP_NUM_LINES];
+	int i = 0;
+	switch (page) {
+	case 1: {
+		title = "DS Controls (right handed):";
+		ADD_BIND("Pad Left", "Left mouse button");
+		ADD_BIND("Pad Right", "Right mouse button");
+		ADD_BIND("Pad Up", "Mouse hover mode (no click)");
+		ADD_BIND("Pad Down", "Skip dialog line (some games)");
+		ADD_BIND("Start", "Pause/Game menu");
+		ADD_BIND("Select", "DS Options menu");
+		ADD_BIND("B", "Skip cutscenes");
+		ADD_BIND("A", "Switch screens");
+		ADD_BIND("Y", "Show/hide debug console");
+		ADD_BIND("X", "Show/hide keyboard");
+		ADD_BIND("L + Pad", "Scroll current touch screen view");
+		ADD_BIND("L + Pen", "Scroll current touch screen view");
+		ADD_BIND("L + B", "Zoom in");
+		ADD_BIND("L + A", "Zoom out");
+		break;
+	}
+
+	case 2: {
+		title = "DS Controls (left handed):";
+		ADD_BIND("Y", "Left mouse button");
+		ADD_BIND("A", "Right mouse button");
+		ADD_BIND("X", "Mouse hover mode (no click)");
+		ADD_BIND("B", "Skip dialog line (some games)");
+		ADD_BIND("Start", "Pause/Game menu");
+		ADD_BIND("Select", "DS Options menu");
+		ADD_BIND("Pad Down", "Skip cutscenes");
+		ADD_BIND("Pad Up", "Show/hide keyboard");
+		ADD_BIND("Pad Left", "Show/hide debug console");
+		ADD_BIND("Pad Right", "Swap screens");
+		ADD_BIND("R + Pad", "Scroll current touch screen view");
+		ADD_BIND("R + Pen", "Scroll current touch screen view");
+		ADD_BIND("R + B", "Zoom in");
+		ADD_BIND("R + A", "Zoom out");
+		break;
+	}
+
+	case 3: {
+		title = "Indiana Jones Fighting controls:";
+		ADD_BIND("Pad Left", "Move left");
+		ADD_BIND("Pad Right", "Move right");
+		ADD_BIND("Pad Up", "High guard");
+		ADD_BIND("Pad Down", "Guard down");
+		ADD_BIND("Y", "Guard middle");
+		ADD_BIND("X", "Punch high");
+		ADD_BIND("A", "Punch middle");
+		ADD_BIND("B", "Punch low");
+
+		ADD_BIND("L+R", "Hold during bootup to clear SRAM");
+		ADD_BIND("", "(flash cart only)");
+		break;
+	}
+	}
+
+
+	while (i < HELP_NUM_LINES) {
+		ADD_LINE;
+	}
+
+}
+
+}
+
+
+#undef ADD_BIND
+#undef ADD_TEXT
+#undef ADD_LINE
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,64 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _SCUMMHELP_H_
+#define _SCUMMHELP_H_
+
+#include "common/str.h"
+
+namespace DS {
+
+void updateStrings(byte gameId, byte version, Common::Platform platform,
+			int page, Common::String &title, Common::String *&key, Common::String *&dsc);
+			
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _SCUMMHELP_H_
+#define _SCUMMHELP_H_
+
+#include "common/str.h"
+
+namespace DS {
+
+void updateStrings(byte gameId, byte version, Common::Platform platform,
+			int page, Common::String &title, Common::String *&key, Common::String *&dsc);
+			
+}
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/scummhelp.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,626 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+#include <NDS.h>
+#include "touchkeyboard.h"
+#include "keyboard_raw.h"
+#include "keyboard_pal_raw.h"
+#include "dsmain.h"
+#include "osystem_ds.h"
+
+namespace DS {
+
+struct key_data {
+	char keyNum;
+	char x, y;
+	int character;
+	bool pressed;
+};
+
+#define DS_NUM_KEYS 60
+#define DS_SHIFT 0
+#define DS_BACKSPACE 8
+#define DS_RETURN 13
+#define DS_CAPSLOCK 1
+
+
+key_data keys[DS_NUM_KEYS] = {
+	// Key number		x		y		character
+	
+	// Numbers
+	{28,				3,		0,		'1'},
+	{29,				5,		0,		'2'},
+	{30,				7,		0,		'3'},
+	{31,				9,		0,		'4'},
+	{32,				11,		0,		'5'},
+	{33,				13,		0,		'6'},
+	{34,				15,		0,		'7'},
+	{35,				17,		0,		'8'},
+	{36,				19,		0,		'9'},
+	{27,				21,		0,		'0'},
+	{45,				23,		0,		SDLK_MINUS},
+	{50,				25,		0,		SDLK_EQUALS},
+	{52,				27,		0,		SDLK_BACKSPACE},
+
+	// Top row
+	{'Q'-'A' + 1,		4,		2,		'Q'},
+	{'W'-'A' + 1,		6,		2,		'W'},
+	{'E'-'A' + 1,		8,		2,		'E'},
+	{'R'-'A' + 1,		10,		2,		'R'},
+	{'T'-'A' + 1,		12,		2,		'T'},
+	{'Y'-'A' + 1,		14,		2,		'Y'},
+	{'U'-'A' + 1,		16,		2,		'U'},
+	{'I'-'A' + 1,		18,		2,		'I'},
+	{'O'-'A' + 1,		20,		2,		'O'},
+	{'P'-'A' + 1,		22,		2,		'P'},
+	{43,				24,		2,		SDLK_LEFTBRACKET},
+	{44,				26,		2,		SDLK_RIGHTBRACKET},
+
+	// Middle row
+	{55,				3,		4,		DS_CAPSLOCK},
+	{'A'-'A' + 1,		5,		4,		'A'},
+	{'S'-'A' + 1,		7,		4,		'S'},
+	{'D'-'A' + 1,		9,		4,		'D'},
+	{'F'-'A' + 1,		11,		4,		'F'},
+	{'G'-'A' + 1,		13,		4,		'G'},
+	{'H'-'A' + 1,		15,		4,		'H'},
+	{'J'-'A' + 1,		17,		4,		'J'},
+	{'K'-'A' + 1,		19,		4,		'K'},
+	{'L'-'A' + 1,		21,		4,		'L'},
+	{42,				23,		4,		SDLK_SEMICOLON},
+	{41,				25,		4,		SDLK_QUOTE},
+	{46,				27,		4,		SDLK_RETURN},
+
+	// Bottom row
+	{51,				4,		6,		DS_SHIFT},
+	{'Z'-'A' + 1,		6,		6,		'Z'},
+	{'X'-'A' + 1,		8,		6,		'X'},
+	{'C'-'A' + 1,		10,		6,		'C'},
+	{'V'-'A' + 1,		12,		6,		'V'},
+	{'B'-'A' + 1,		14,		6,		'B'},
+	{'N'-'A' + 1,		16,		6,		'N'},
+	{'M'-'A' + 1,		18,		6,		'M'},
+	{38,				20,		6,		SDLK_COMMA},
+	{39,				22,		6,		SDLK_PERIOD},
+	{40,				24,		6,		SDLK_SLASH},
+
+	// Space bar
+	{47,				9,		8,		SDLK_SPACE},
+	{48,				11,		8,		SDLK_SPACE},
+	{48,				13,		8,		SDLK_SPACE},
+	{48,				15,		8,		SDLK_SPACE},
+	{48,				17,		8,		SDLK_SPACE},
+	{49,				19,		8,		SDLK_SPACE},
+
+	// Cursor arrows
+	{52,				27,		8,		SDLK_LEFT},
+	{54,				29,		8,		SDLK_DOWN},
+	{53,				31,		8,		SDLK_RIGHT},
+	{51,				29,		6,		SDLK_UP},
+	
+	// Close button
+	{56,				30,		0,		SDLK_UNKNOWN},
+	
+};
+
+int keyboardX;
+int keyboardY;
+
+int mapBase;
+int tileBase;
+
+bool shiftState;
+bool capsLockState;
+
+bool closed;
+
+void restoreVRAM(int tileBase, int mapBase, u16* saveSpace) {
+	for (int r = 0; r < 32 * 32; r++) {
+		((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = *saveSpace++;
+	}
+	
+	for (int r = 0; r < 4096; r++) {
+		((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r]	= *saveSpace++;
+	}
+}
+
+void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
+
+
+	for (int r = 0; r < 32 * 32; r++) {
+//		*saveSpace++ = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r];
+		((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = 127;
+	}
+	
+	for (int r = 0; r < 4096; r++) {
+//		*saveSpace++ = ((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r];
+		((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r] = ((u16 *) (keyboard_raw))[r];
+	}
+	
+	for (int r = 0; r < 16; r++) {
+		BG_PALETTE_SUB[r] = ((u16 *) (keyboard_pal_raw))[r];
+	}
+
+	for (int r = 0; r < 16; r++) {
+		int col = ((u16 *) (keyboard_pal_raw))[r];
+		
+		int red = col & 0x001F;
+		int green = (col & 0x03E0) >> 5;
+		int blue = (col & 0x7C00) >> 10;
+		
+		red = (red * 8) / 16;
+		green = (green * 8) / 16;
+		blue = (blue * 8) / 16;
+				
+		BG_PALETTE_SUB[16 + r] = red | (green << 5) | (blue << 10);
+	}
+	
+	keyboardX = -2;
+	keyboardY = 2;
+	
+	mapBase = mapBase;
+	tileBase = tileBase;
+	
+	shiftState = false;
+	capsLockState = false;
+	
+	int x = keyboardX;
+	int y = keyboardY;
+	
+	u16* base = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase));
+	
+	for (int r = 0; r < DS_NUM_KEYS; r++) {
+		base[(y + keys[r].y) * 32 + x + keys[r].x] = keys[r].keyNum * 2;
+		base[(y + keys[r].y) * 32 + x + keys[r].x + 1] = keys[r].keyNum * 2 + 1;
+		
+		base[(y + keys[r].y + 1) * 32 + x + keys[r].x] = 128 + keys[r].keyNum * 2;
+		base[(y + keys[r].y + 1) * 32 + x + keys[r].x + 1] = 128 + keys[r].keyNum * 2 + 1;
+		
+		keys[r].pressed = false;
+	}
+	
+	closed = false;
+}
+
+bool getKeyboardClosed() {
+	return closed;
+}
+
+void setKeyHighlight(int key, bool highlight) {
+	u16* base = ((u16 *) SCREEN_BASE_BLOCK_SUB(DS::mapBase));
+
+	if (highlight) {
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] |= 0x1000;
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] |= 0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
+	} else {
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] &= ~0x1000;
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] &= ~0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
+	}
+}
+
+void addKeyboardEvents() {
+	if (DS::getPenDown()) {
+		int x = IPC->touchXpx;
+		int y = IPC->touchYpx;
+		
+		int tx = (x >> 3) - keyboardX;
+		int ty = (y >> 3) - keyboardY;
+		
+//		consolePrintf("x=%d y=%d\n", tx, ty);
+		
+		for (int r = 0; r < DS_NUM_KEYS; r++) {
+			if (( (tx >= keys[r].x) && (tx <= keys[r].x + 1)) && 
+				   (ty >= keys[r].y) && (ty <= keys[r].y + 1)) {
+			   	OSystem_DS* system = OSystem_DS::instance();
+				OSystem::Event event;
+				
+//				consolePrintf("Key: %d\n", r);
+				if ((keys[r].character == SDLK_UNKNOWN)) {
+					// Close button
+					DS::closed = true;
+				} else	if ((keys[r].character >= '0') && (keys[r].character <= '9')) {
+					event.kbd.ascii = keys[r].character;
+					event.kbd.keycode = 0;
+				
+				} else if ((keys[r].character >= 'A') && (keys[r].character <= 'Z')) {
+					
+					if ((!DS::shiftState) && (!DS::capsLockState)) {
+						event.kbd.ascii = keys[r].character + 32; // Make key lowercase.
+					} else {
+						event.kbd.ascii = keys[r].character;
+					}
+					
+					event.kbd.keycode = event.kbd.ascii;
+				} else {
+					event.kbd.ascii = keys[r].character;
+					event.kbd.keycode = keys[r].character;
+				}				
+			
+				
+				
+				//event.kbd.keycode = keys[r].character;		
+				//event.kbd.ascii = keys[r].character;		
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+				
+				switch (keys[r].character) {
+					case DS_SHIFT: {
+						DS::shiftState = !DS::shiftState;
+						DS::setKeyHighlight(r, DS::shiftState);
+						break;
+					}
+					
+					case DS_CAPSLOCK: {
+						DS::capsLockState = !DS::capsLockState;
+						DS::setKeyHighlight(r, DS::capsLockState);
+						break;
+					}
+					
+					default: {
+						DS::setKeyHighlight(r, true);
+						keys[r].pressed = true;
+						
+						if (DS::shiftState) {
+							DS::shiftState = false;
+							for (int t = 0; t < DS_NUM_KEYS; t++) {
+								if (keys[t].character == DS_SHIFT) {
+									DS::setKeyHighlight(t, false);
+								}
+							}
+						}
+						break;
+					}
+				}
+				
+			}
+		}
+	}
+	
+	if (DS::getPenReleased()) {
+		for (int r = 0; r < DS_NUM_KEYS; r++) {
+			if (keys[r].pressed) {
+				DS::setKeyHighlight(r, false);
+				keys[r].pressed = false;
+			}
+		}	
+	}
+}
+
+}
+
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+#include <NDS.h>
+#include "touchkeyboard.h"
+#include "keyboard_raw.h"
+#include "keyboard_pal_raw.h"
+#include "dsmain.h"
+#include "osystem_ds.h"
+
+namespace DS {
+
+struct key_data {
+	char keyNum;
+	char x, y;
+	int character;
+	bool pressed;
+};
+
+#define DS_NUM_KEYS 60
+#define DS_SHIFT 0
+#define DS_BACKSPACE 8
+#define DS_RETURN 13
+#define DS_CAPSLOCK 1
+
+
+key_data keys[DS_NUM_KEYS] = {
+	// Key number		x		y		character
+	
+	// Numbers
+	{28,				3,		0,		'1'},
+	{29,				5,		0,		'2'},
+	{30,				7,		0,		'3'},
+	{31,				9,		0,		'4'},
+	{32,				11,		0,		'5'},
+	{33,				13,		0,		'6'},
+	{34,				15,		0,		'7'},
+	{35,				17,		0,		'8'},
+	{36,				19,		0,		'9'},
+	{27,				21,		0,		'0'},
+	{45,				23,		0,		SDLK_MINUS},
+	{50,				25,		0,		SDLK_EQUALS},
+	{52,				27,		0,		SDLK_BACKSPACE},
+
+	// Top row
+	{'Q'-'A' + 1,		4,		2,		'Q'},
+	{'W'-'A' + 1,		6,		2,		'W'},
+	{'E'-'A' + 1,		8,		2,		'E'},
+	{'R'-'A' + 1,		10,		2,		'R'},
+	{'T'-'A' + 1,		12,		2,		'T'},
+	{'Y'-'A' + 1,		14,		2,		'Y'},
+	{'U'-'A' + 1,		16,		2,		'U'},
+	{'I'-'A' + 1,		18,		2,		'I'},
+	{'O'-'A' + 1,		20,		2,		'O'},
+	{'P'-'A' + 1,		22,		2,		'P'},
+	{43,				24,		2,		SDLK_LEFTBRACKET},
+	{44,				26,		2,		SDLK_RIGHTBRACKET},
+
+	// Middle row
+	{55,				3,		4,		DS_CAPSLOCK},
+	{'A'-'A' + 1,		5,		4,		'A'},
+	{'S'-'A' + 1,		7,		4,		'S'},
+	{'D'-'A' + 1,		9,		4,		'D'},
+	{'F'-'A' + 1,		11,		4,		'F'},
+	{'G'-'A' + 1,		13,		4,		'G'},
+	{'H'-'A' + 1,		15,		4,		'H'},
+	{'J'-'A' + 1,		17,		4,		'J'},
+	{'K'-'A' + 1,		19,		4,		'K'},
+	{'L'-'A' + 1,		21,		4,		'L'},
+	{42,				23,		4,		SDLK_SEMICOLON},
+	{41,				25,		4,		SDLK_QUOTE},
+	{46,				27,		4,		SDLK_RETURN},
+
+	// Bottom row
+	{51,				4,		6,		DS_SHIFT},
+	{'Z'-'A' + 1,		6,		6,		'Z'},
+	{'X'-'A' + 1,		8,		6,		'X'},
+	{'C'-'A' + 1,		10,		6,		'C'},
+	{'V'-'A' + 1,		12,		6,		'V'},
+	{'B'-'A' + 1,		14,		6,		'B'},
+	{'N'-'A' + 1,		16,		6,		'N'},
+	{'M'-'A' + 1,		18,		6,		'M'},
+	{38,				20,		6,		SDLK_COMMA},
+	{39,				22,		6,		SDLK_PERIOD},
+	{40,				24,		6,		SDLK_SLASH},
+
+	// Space bar
+	{47,				9,		8,		SDLK_SPACE},
+	{48,				11,		8,		SDLK_SPACE},
+	{48,				13,		8,		SDLK_SPACE},
+	{48,				15,		8,		SDLK_SPACE},
+	{48,				17,		8,		SDLK_SPACE},
+	{49,				19,		8,		SDLK_SPACE},
+
+	// Cursor arrows
+	{52,				27,		8,		SDLK_LEFT},
+	{54,				29,		8,		SDLK_DOWN},
+	{53,				31,		8,		SDLK_RIGHT},
+	{51,				29,		6,		SDLK_UP},
+	
+	// Close button
+	{56,				30,		0,		SDLK_UNKNOWN},
+	
+};
+
+int keyboardX;
+int keyboardY;
+
+int mapBase;
+int tileBase;
+
+bool shiftState;
+bool capsLockState;
+
+bool closed;
+
+void restoreVRAM(int tileBase, int mapBase, u16* saveSpace) {
+	for (int r = 0; r < 32 * 32; r++) {
+		((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = *saveSpace++;
+	}
+	
+	for (int r = 0; r < 4096; r++) {
+		((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r]	= *saveSpace++;
+	}
+}
+
+void drawKeyboard(int tileBase, int mapBase, u16* saveSpace) {
+
+
+	for (int r = 0; r < 32 * 32; r++) {
+//		*saveSpace++ = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r];
+		((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = 127;
+	}
+	
+	for (int r = 0; r < 4096; r++) {
+//		*saveSpace++ = ((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r];
+		((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r] = ((u16 *) (keyboard_raw))[r];
+	}
+	
+	for (int r = 0; r < 16; r++) {
+		BG_PALETTE_SUB[r] = ((u16 *) (keyboard_pal_raw))[r];
+	}
+
+	for (int r = 0; r < 16; r++) {
+		int col = ((u16 *) (keyboard_pal_raw))[r];
+		
+		int red = col & 0x001F;
+		int green = (col & 0x03E0) >> 5;
+		int blue = (col & 0x7C00) >> 10;
+		
+		red = (red * 8) / 16;
+		green = (green * 8) / 16;
+		blue = (blue * 8) / 16;
+				
+		BG_PALETTE_SUB[16 + r] = red | (green << 5) | (blue << 10);
+	}
+	
+	keyboardX = -2;
+	keyboardY = 2;
+	
+	mapBase = mapBase;
+	tileBase = tileBase;
+	
+	shiftState = false;
+	capsLockState = false;
+	
+	int x = keyboardX;
+	int y = keyboardY;
+	
+	u16* base = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase));
+	
+	for (int r = 0; r < DS_NUM_KEYS; r++) {
+		base[(y + keys[r].y) * 32 + x + keys[r].x] = keys[r].keyNum * 2;
+		base[(y + keys[r].y) * 32 + x + keys[r].x + 1] = keys[r].keyNum * 2 + 1;
+		
+		base[(y + keys[r].y + 1) * 32 + x + keys[r].x] = 128 + keys[r].keyNum * 2;
+		base[(y + keys[r].y + 1) * 32 + x + keys[r].x + 1] = 128 + keys[r].keyNum * 2 + 1;
+		
+		keys[r].pressed = false;
+	}
+	
+	closed = false;
+}
+
+bool getKeyboardClosed() {
+	return closed;
+}
+
+void setKeyHighlight(int key, bool highlight) {
+	u16* base = ((u16 *) SCREEN_BASE_BLOCK_SUB(DS::mapBase));
+
+	if (highlight) {
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] |= 0x1000;
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] |= 0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
+	} else {
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] &= ~0x1000;
+		base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] &= ~0x1000;
+		base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
+	}
+}
+
+void addKeyboardEvents() {
+	if (DS::getPenDown()) {
+		int x = IPC->touchXpx;
+		int y = IPC->touchYpx;
+		
+		int tx = (x >> 3) - keyboardX;
+		int ty = (y >> 3) - keyboardY;
+		
+//		consolePrintf("x=%d y=%d\n", tx, ty);
+		
+		for (int r = 0; r < DS_NUM_KEYS; r++) {
+			if (( (tx >= keys[r].x) && (tx <= keys[r].x + 1)) && 
+				   (ty >= keys[r].y) && (ty <= keys[r].y + 1)) {
+			   	OSystem_DS* system = OSystem_DS::instance();
+				OSystem::Event event;
+				
+//				consolePrintf("Key: %d\n", r);
+				if ((keys[r].character == SDLK_UNKNOWN)) {
+					// Close button
+					DS::closed = true;
+				} else	if ((keys[r].character >= '0') && (keys[r].character <= '9')) {
+					event.kbd.ascii = keys[r].character;
+					event.kbd.keycode = 0;
+				
+				} else if ((keys[r].character >= 'A') && (keys[r].character <= 'Z')) {
+					
+					if ((!DS::shiftState) && (!DS::capsLockState)) {
+						event.kbd.ascii = keys[r].character + 32; // Make key lowercase.
+					} else {
+						event.kbd.ascii = keys[r].character;
+					}
+					
+					event.kbd.keycode = event.kbd.ascii;
+				} else {
+					event.kbd.ascii = keys[r].character;
+					event.kbd.keycode = keys[r].character;
+				}				
+			
+				
+				
+				//event.kbd.keycode = keys[r].character;		
+				//event.kbd.ascii = keys[r].character;		
+				event.type = OSystem::EVENT_KEYDOWN;
+				event.kbd.flags = 0;
+				system->addEvent(event);
+
+				event.type = OSystem::EVENT_KEYUP;
+				system->addEvent(event);
+				
+				switch (keys[r].character) {
+					case DS_SHIFT: {
+						DS::shiftState = !DS::shiftState;
+						DS::setKeyHighlight(r, DS::shiftState);
+						break;
+					}
+					
+					case DS_CAPSLOCK: {
+						DS::capsLockState = !DS::capsLockState;
+						DS::setKeyHighlight(r, DS::capsLockState);
+						break;
+					}
+					
+					default: {
+						DS::setKeyHighlight(r, true);
+						keys[r].pressed = true;
+						
+						if (DS::shiftState) {
+							DS::shiftState = false;
+							for (int t = 0; t < DS_NUM_KEYS; t++) {
+								if (keys[t].character == DS_SHIFT) {
+									DS::setKeyHighlight(t, false);
+								}
+							}
+						}
+						break;
+					}
+				}
+				
+			}
+		}
+	}
+	
+	if (DS::getPenReleased()) {
+		for (int r = 0; r < DS_NUM_KEYS; r++) {
+			if (keys[r].pressed) {
+				DS::setKeyHighlight(r, false);
+				keys[r].pressed = false;
+			}
+		}	
+	}
+}
+
+}
+


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,202 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _TOUCHKEYBOARD_H_
+#define _TOUCHKEYBOARD_H_
+
+namespace DS {
+
+enum  	SDLKey {
+  SDLK_UNKNOWN = 0, SDLK_FIRST = 0, SDLK_BACKSPACE = 8, SDLK_TAB = 9,
+  SDLK_CLEAR = 12, SDLK_RETURN = 13, SDLK_PAUSE = 19, SDLK_ESCAPE = 27,
+  SDLK_SPACE = 32, SDLK_EXCLAIM = 33, SDLK_QUOTEDBL = 34, SDLK_HASH = 35,
+  SDLK_DOLLAR = 36, SDLK_AMPERSAND = 38, SDLK_QUOTE = 39, SDLK_LEFTPAREN = 40,
+  SDLK_RIGHTPAREN = 41, SDLK_ASTERISK = 42, SDLK_PLUS = 43, SDLK_COMMA = 44,
+  SDLK_MINUS = 45, SDLK_PERIOD = 46, SDLK_SLASH = 47, SDLK_0 = 48,
+  SDLK_1 = 49, SDLK_2 = 50, SDLK_3 = 51, SDLK_4 = 52,
+  SDLK_5 = 53, SDLK_6 = 54, SDLK_7 = 55, SDLK_8 = 56,
+  SDLK_9 = 57, SDLK_COLON = 58, SDLK_SEMICOLON = 59, SDLK_LESS = 60,
+  SDLK_EQUALS = 61, SDLK_GREATER = 62, SDLK_QUESTION = 63, SDLK_AT = 64,
+  SDLK_LEFTBRACKET = 91, SDLK_BACKSLASH = 92, SDLK_RIGHTBRACKET = 93, SDLK_CARET = 94,
+  SDLK_UNDERSCORE = 95, SDLK_BACKQUOTE = 96, SDLK_a = 97, SDLK_b = 98,
+  SDLK_c = 99, SDLK_d = 100, SDLK_e = 101, SDLK_f = 102,
+  SDLK_g = 103, SDLK_h = 104, SDLK_i = 105, SDLK_j = 106,
+  SDLK_k = 107, SDLK_l = 108, SDLK_m = 109, SDLK_n = 110,
+  SDLK_o = 111, SDLK_p = 112, SDLK_q = 113, SDLK_r = 114,
+  SDLK_s = 115, SDLK_t = 116, SDLK_u = 117, SDLK_v = 118,
+  SDLK_w = 119, SDLK_x = 120, SDLK_y = 121, SDLK_z = 122,
+  SDLK_DELETE = 127, SDLK_WORLD_0 = 160, SDLK_WORLD_1 = 161, SDLK_WORLD_2 = 162,
+  SDLK_WORLD_3 = 163, SDLK_WORLD_4 = 164, SDLK_WORLD_5 = 165, SDLK_WORLD_6 = 166,
+  SDLK_WORLD_7 = 167, SDLK_WORLD_8 = 168, SDLK_WORLD_9 = 169, SDLK_WORLD_10 = 170,
+  SDLK_WORLD_11 = 171, SDLK_WORLD_12 = 172, SDLK_WORLD_13 = 173, SDLK_WORLD_14 = 174,
+  SDLK_WORLD_15 = 175, SDLK_WORLD_16 = 176, SDLK_WORLD_17 = 177, SDLK_WORLD_18 = 178,
+  SDLK_WORLD_19 = 179, SDLK_WORLD_20 = 180, SDLK_WORLD_21 = 181, SDLK_WORLD_22 = 182,
+  SDLK_WORLD_23 = 183, SDLK_WORLD_24 = 184, SDLK_WORLD_25 = 185, SDLK_WORLD_26 = 186,
+  SDLK_WORLD_27 = 187, SDLK_WORLD_28 = 188, SDLK_WORLD_29 = 189, SDLK_WORLD_30 = 190,
+  SDLK_WORLD_31 = 191, SDLK_WORLD_32 = 192, SDLK_WORLD_33 = 193, SDLK_WORLD_34 = 194,
+  SDLK_WORLD_35 = 195, SDLK_WORLD_36 = 196, SDLK_WORLD_37 = 197, SDLK_WORLD_38 = 198,
+  SDLK_WORLD_39 = 199, SDLK_WORLD_40 = 200, SDLK_WORLD_41 = 201, SDLK_WORLD_42 = 202,
+  SDLK_WORLD_43 = 203, SDLK_WORLD_44 = 204, SDLK_WORLD_45 = 205, SDLK_WORLD_46 = 206,
+  SDLK_WORLD_47 = 207, SDLK_WORLD_48 = 208, SDLK_WORLD_49 = 209, SDLK_WORLD_50 = 210,
+  SDLK_WORLD_51 = 211, SDLK_WORLD_52 = 212, SDLK_WORLD_53 = 213, SDLK_WORLD_54 = 214,
+  SDLK_WORLD_55 = 215, SDLK_WORLD_56 = 216, SDLK_WORLD_57 = 217, SDLK_WORLD_58 = 218,
+  SDLK_WORLD_59 = 219, SDLK_WORLD_60 = 220, SDLK_WORLD_61 = 221, SDLK_WORLD_62 = 222,
+  SDLK_WORLD_63 = 223, SDLK_WORLD_64 = 224, SDLK_WORLD_65 = 225, SDLK_WORLD_66 = 226,
+  SDLK_WORLD_67 = 227, SDLK_WORLD_68 = 228, SDLK_WORLD_69 = 229, SDLK_WORLD_70 = 230,
+  SDLK_WORLD_71 = 231, SDLK_WORLD_72 = 232, SDLK_WORLD_73 = 233, SDLK_WORLD_74 = 234,
+  SDLK_WORLD_75 = 235, SDLK_WORLD_76 = 236, SDLK_WORLD_77 = 237, SDLK_WORLD_78 = 238,
+  SDLK_WORLD_79 = 239, SDLK_WORLD_80 = 240, SDLK_WORLD_81 = 241, SDLK_WORLD_82 = 242,
+  SDLK_WORLD_83 = 243, SDLK_WORLD_84 = 244, SDLK_WORLD_85 = 245, SDLK_WORLD_86 = 246,
+  SDLK_WORLD_87 = 247, SDLK_WORLD_88 = 248, SDLK_WORLD_89 = 249, SDLK_WORLD_90 = 250,
+  SDLK_WORLD_91 = 251, SDLK_WORLD_92 = 252, SDLK_WORLD_93 = 253, SDLK_WORLD_94 = 254,
+  SDLK_WORLD_95 = 255, SDLK_KP0 = 256, SDLK_KP1 = 257, SDLK_KP2 = 258,
+  SDLK_KP3 = 259, SDLK_KP4 = 260, SDLK_KP5 = 261, SDLK_KP6 = 262,
+  SDLK_KP7 = 263, SDLK_KP8 = 264, SDLK_KP9 = 265, SDLK_KP_PERIOD = 266,
+  SDLK_KP_DIVIDE = 267, SDLK_KP_MULTIPLY = 268, SDLK_KP_MINUS = 269, SDLK_KP_PLUS = 270,
+  SDLK_KP_ENTER = 271, SDLK_KP_EQUALS = 272, SDLK_UP = 273, SDLK_DOWN = 274,
+  SDLK_RIGHT = 275, SDLK_LEFT = 276, SDLK_INSERT = 277, SDLK_HOME = 278,
+  SDLK_END = 279, SDLK_PAGEUP = 280, SDLK_PAGEDOWN = 281, SDLK_F1 = 282,
+  SDLK_F2 = 283, SDLK_F3 = 284, SDLK_F4 = 285, SDLK_F5 = 286,
+  SDLK_F6 = 287, SDLK_F7 = 288, SDLK_F8 = 289, SDLK_F9 = 290,
+  SDLK_F10 = 291, SDLK_F11 = 292, SDLK_F12 = 293, SDLK_F13 = 294,
+  SDLK_F14 = 295, SDLK_F15 = 296, SDLK_NUMLOCK = 300, SDLK_CAPSLOCK = 301,
+  SDLK_SCROLLOCK = 302, SDLK_RSHIFT = 303, SDLK_LSHIFT = 304, SDLK_RCTRL = 305,
+  SDLK_LCTRL = 306, SDLK_RALT = 307, SDLK_LALT = 308, SDLK_RMETA = 309,
+  SDLK_LMETA = 310, SDLK_LSUPER = 311, SDLK_RSUPER = 312, SDLK_MODE = 313,
+  SDLK_COMPOSE = 314, SDLK_HELP = 315, SDLK_PRINT = 316, SDLK_SYSREQ = 317,
+  SDLK_BREAK = 318, SDLK_MENU = 319, SDLK_POWER = 320, SDLK_EURO = 321,
+  SDLK_UNDO = 322, SDLK_LAST
+};
+
+enum  	SDLMod {
+  KMOD_NONE = 0x0000, KMOD_LSHIFT = 0x0001, KMOD_RSHIFT = 0x0002, KMOD_LCTRL = 0x0040,
+  KMOD_RCTRL = 0x0080, KMOD_LALT = 0x0100, KMOD_RALT = 0x0200, KMOD_LMETA = 0x0400,
+  KMOD_RMETA = 0x0800, KMOD_NUM = 0x1000, KMOD_CAPS = 0x2000, KMOD_MODE = 0x4000,
+  KMOD_RESERVED = 0x8000
+};
+
+void drawKeyboard(int tileBase, int mapBase, u16* saveSpace);
+void restoreVRAM(int tileBase, int mapBase, u16* saveSpace);
+void addKeyboardEvents();
+bool getKeyboardClosed();
+
+}
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _TOUCHKEYBOARD_H_
+#define _TOUCHKEYBOARD_H_
+
+namespace DS {
+
+enum  	SDLKey {
+  SDLK_UNKNOWN = 0, SDLK_FIRST = 0, SDLK_BACKSPACE = 8, SDLK_TAB = 9,
+  SDLK_CLEAR = 12, SDLK_RETURN = 13, SDLK_PAUSE = 19, SDLK_ESCAPE = 27,
+  SDLK_SPACE = 32, SDLK_EXCLAIM = 33, SDLK_QUOTEDBL = 34, SDLK_HASH = 35,
+  SDLK_DOLLAR = 36, SDLK_AMPERSAND = 38, SDLK_QUOTE = 39, SDLK_LEFTPAREN = 40,
+  SDLK_RIGHTPAREN = 41, SDLK_ASTERISK = 42, SDLK_PLUS = 43, SDLK_COMMA = 44,
+  SDLK_MINUS = 45, SDLK_PERIOD = 46, SDLK_SLASH = 47, SDLK_0 = 48,
+  SDLK_1 = 49, SDLK_2 = 50, SDLK_3 = 51, SDLK_4 = 52,
+  SDLK_5 = 53, SDLK_6 = 54, SDLK_7 = 55, SDLK_8 = 56,
+  SDLK_9 = 57, SDLK_COLON = 58, SDLK_SEMICOLON = 59, SDLK_LESS = 60,
+  SDLK_EQUALS = 61, SDLK_GREATER = 62, SDLK_QUESTION = 63, SDLK_AT = 64,
+  SDLK_LEFTBRACKET = 91, SDLK_BACKSLASH = 92, SDLK_RIGHTBRACKET = 93, SDLK_CARET = 94,
+  SDLK_UNDERSCORE = 95, SDLK_BACKQUOTE = 96, SDLK_a = 97, SDLK_b = 98,
+  SDLK_c = 99, SDLK_d = 100, SDLK_e = 101, SDLK_f = 102,
+  SDLK_g = 103, SDLK_h = 104, SDLK_i = 105, SDLK_j = 106,
+  SDLK_k = 107, SDLK_l = 108, SDLK_m = 109, SDLK_n = 110,
+  SDLK_o = 111, SDLK_p = 112, SDLK_q = 113, SDLK_r = 114,
+  SDLK_s = 115, SDLK_t = 116, SDLK_u = 117, SDLK_v = 118,
+  SDLK_w = 119, SDLK_x = 120, SDLK_y = 121, SDLK_z = 122,
+  SDLK_DELETE = 127, SDLK_WORLD_0 = 160, SDLK_WORLD_1 = 161, SDLK_WORLD_2 = 162,
+  SDLK_WORLD_3 = 163, SDLK_WORLD_4 = 164, SDLK_WORLD_5 = 165, SDLK_WORLD_6 = 166,
+  SDLK_WORLD_7 = 167, SDLK_WORLD_8 = 168, SDLK_WORLD_9 = 169, SDLK_WORLD_10 = 170,
+  SDLK_WORLD_11 = 171, SDLK_WORLD_12 = 172, SDLK_WORLD_13 = 173, SDLK_WORLD_14 = 174,
+  SDLK_WORLD_15 = 175, SDLK_WORLD_16 = 176, SDLK_WORLD_17 = 177, SDLK_WORLD_18 = 178,
+  SDLK_WORLD_19 = 179, SDLK_WORLD_20 = 180, SDLK_WORLD_21 = 181, SDLK_WORLD_22 = 182,
+  SDLK_WORLD_23 = 183, SDLK_WORLD_24 = 184, SDLK_WORLD_25 = 185, SDLK_WORLD_26 = 186,
+  SDLK_WORLD_27 = 187, SDLK_WORLD_28 = 188, SDLK_WORLD_29 = 189, SDLK_WORLD_30 = 190,
+  SDLK_WORLD_31 = 191, SDLK_WORLD_32 = 192, SDLK_WORLD_33 = 193, SDLK_WORLD_34 = 194,
+  SDLK_WORLD_35 = 195, SDLK_WORLD_36 = 196, SDLK_WORLD_37 = 197, SDLK_WORLD_38 = 198,
+  SDLK_WORLD_39 = 199, SDLK_WORLD_40 = 200, SDLK_WORLD_41 = 201, SDLK_WORLD_42 = 202,
+  SDLK_WORLD_43 = 203, SDLK_WORLD_44 = 204, SDLK_WORLD_45 = 205, SDLK_WORLD_46 = 206,
+  SDLK_WORLD_47 = 207, SDLK_WORLD_48 = 208, SDLK_WORLD_49 = 209, SDLK_WORLD_50 = 210,
+  SDLK_WORLD_51 = 211, SDLK_WORLD_52 = 212, SDLK_WORLD_53 = 213, SDLK_WORLD_54 = 214,
+  SDLK_WORLD_55 = 215, SDLK_WORLD_56 = 216, SDLK_WORLD_57 = 217, SDLK_WORLD_58 = 218,
+  SDLK_WORLD_59 = 219, SDLK_WORLD_60 = 220, SDLK_WORLD_61 = 221, SDLK_WORLD_62 = 222,
+  SDLK_WORLD_63 = 223, SDLK_WORLD_64 = 224, SDLK_WORLD_65 = 225, SDLK_WORLD_66 = 226,
+  SDLK_WORLD_67 = 227, SDLK_WORLD_68 = 228, SDLK_WORLD_69 = 229, SDLK_WORLD_70 = 230,
+  SDLK_WORLD_71 = 231, SDLK_WORLD_72 = 232, SDLK_WORLD_73 = 233, SDLK_WORLD_74 = 234,
+  SDLK_WORLD_75 = 235, SDLK_WORLD_76 = 236, SDLK_WORLD_77 = 237, SDLK_WORLD_78 = 238,
+  SDLK_WORLD_79 = 239, SDLK_WORLD_80 = 240, SDLK_WORLD_81 = 241, SDLK_WORLD_82 = 242,
+  SDLK_WORLD_83 = 243, SDLK_WORLD_84 = 244, SDLK_WORLD_85 = 245, SDLK_WORLD_86 = 246,
+  SDLK_WORLD_87 = 247, SDLK_WORLD_88 = 248, SDLK_WORLD_89 = 249, SDLK_WORLD_90 = 250,
+  SDLK_WORLD_91 = 251, SDLK_WORLD_92 = 252, SDLK_WORLD_93 = 253, SDLK_WORLD_94 = 254,
+  SDLK_WORLD_95 = 255, SDLK_KP0 = 256, SDLK_KP1 = 257, SDLK_KP2 = 258,
+  SDLK_KP3 = 259, SDLK_KP4 = 260, SDLK_KP5 = 261, SDLK_KP6 = 262,
+  SDLK_KP7 = 263, SDLK_KP8 = 264, SDLK_KP9 = 265, SDLK_KP_PERIOD = 266,
+  SDLK_KP_DIVIDE = 267, SDLK_KP_MULTIPLY = 268, SDLK_KP_MINUS = 269, SDLK_KP_PLUS = 270,
+  SDLK_KP_ENTER = 271, SDLK_KP_EQUALS = 272, SDLK_UP = 273, SDLK_DOWN = 274,
+  SDLK_RIGHT = 275, SDLK_LEFT = 276, SDLK_INSERT = 277, SDLK_HOME = 278,
+  SDLK_END = 279, SDLK_PAGEUP = 280, SDLK_PAGEDOWN = 281, SDLK_F1 = 282,
+  SDLK_F2 = 283, SDLK_F3 = 284, SDLK_F4 = 285, SDLK_F5 = 286,
+  SDLK_F6 = 287, SDLK_F7 = 288, SDLK_F8 = 289, SDLK_F9 = 290,
+  SDLK_F10 = 291, SDLK_F11 = 292, SDLK_F12 = 293, SDLK_F13 = 294,
+  SDLK_F14 = 295, SDLK_F15 = 296, SDLK_NUMLOCK = 300, SDLK_CAPSLOCK = 301,
+  SDLK_SCROLLOCK = 302, SDLK_RSHIFT = 303, SDLK_LSHIFT = 304, SDLK_RCTRL = 305,
+  SDLK_LCTRL = 306, SDLK_RALT = 307, SDLK_LALT = 308, SDLK_RMETA = 309,
+  SDLK_LMETA = 310, SDLK_LSUPER = 311, SDLK_RSUPER = 312, SDLK_MODE = 313,
+  SDLK_COMPOSE = 314, SDLK_HELP = 315, SDLK_PRINT = 316, SDLK_SYSREQ = 317,
+  SDLK_BREAK = 318, SDLK_MENU = 319, SDLK_POWER = 320, SDLK_EURO = 321,
+  SDLK_UNDO = 322, SDLK_LAST
+};
+
+enum  	SDLMod {
+  KMOD_NONE = 0x0000, KMOD_LSHIFT = 0x0001, KMOD_RSHIFT = 0x0002, KMOD_LCTRL = 0x0040,
+  KMOD_RCTRL = 0x0080, KMOD_LALT = 0x0100, KMOD_RALT = 0x0200, KMOD_LMETA = 0x0400,
+  KMOD_RMETA = 0x0800, KMOD_NUM = 0x1000, KMOD_CAPS = 0x2000, KMOD_MODE = 0x4000,
+  KMOD_RESERVED = 0x8000
+};
+
+void drawKeyboard(int tileBase, int mapBase, u16* saveSpace);
+void restoreVRAM(int tileBase, int mapBase, u16* saveSpace);
+void addKeyboardEvents();
+bool getKeyboardClosed();
+
+}
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/touchkeyboard.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/zipreader.cpp
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/zipreader.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/zipreader.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,442 @@
+/* Zip File Reader
+ * Copyright (C) 2002-2004 Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 
+ */
+
+
+#include "stdafx.h"
+#include "zipreader.h"
+
+#define SWAP_U16(v) (((v & 0xFF) << 8) + (v & 0xFF00))
+#define SWAP_U32(v) ((SWAP_U16((v & 0XFFFF0000) >> 16) + (SWAP_U16(v & 0x0000FFFF) << 16)))
+
+
+ZipFile::ZipFile() {
+	// Locate a zip file in cartridge memory space
+	
+	consolePrintf("ZIP file check...");
+	
+	char* p = (char *) ZF_SEARCH_START;
+	bool found = false;
+	
+	_zipFile = NULL;
+	
+	while ((p != (char *) ZF_SEARCH_END) && (!found)) {
+		// Zip file header is: 0x504B0304
+		
+		if ( (*p == 0x50) && (*(p + 1) == 0x4B) && (*(p + 2) == 0x03) && (*(p + 3) == 0x04) ) {
+			// Found header!
+			found = true;
+			_zipFile = p;
+		}
+	
+		if (!found) p += ZF_SEARCH_STRIDE;
+		
+	}
+
+	if (_zipFile) {
+		consolePrintf("Ok!\n");
+	} else {
+		consolePrintf("Not in use!\n");
+		return;
+	}
+	
+	changeToRoot();
+	restartFile();
+	
+	if (_currentFile->compSize != (u32) getFileSize()) {
+		consolePrintf("Error: ZIP file contains compression!\n");
+	}
+	
+	_allFilesVisible = false;
+}
+
+bool ZipFile::isReady() {
+	return _zipFile != NULL;
+}
+
+bool ZipFile::restartFile() {
+	_currentFile = (FileHeader *) _zipFile;
+	char name[128];
+	getFileName(name);
+
+	bool more = true;
+
+	while (!currentFileInFolder() && more) {
+		char name[128];
+		getFileName(name);
+		more = skipFile();
+	}
+	
+	return more;
+}
+
+bool ZipFile::currentFileInFolder() {
+	char name[128];
+	
+	if (_allFilesVisible) return true;
+	
+	getFileName(name);
+	
+	if (_directory[0] == 0) { // Root directory
+		name[strlen(name) - 1] = 0;
+		return !strchr(name, '\\'); 	// Not in root if contains a / character before the last character
+	} else {
+/*		if (name starts with directory && it's not the directory
+			&& (no slashes after the directory || it's the last character)
+			&& (slash follows directory)
+	*/
+		if ((strstr(name, _directory) == name) && (strlen(name) != strlen(_directory))	
+			&& ((strchr(name + strlen(_directory) + 1, '\\') == NULL)
+			|| (strchr(name + strlen(_directory) + 1, '\\') == name + strlen(name) - 1))
+			&& (*(name + strlen(_directory)) == '\\')) {
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+void ZipFile::getFileName(char* name) {
+	strncpy(name, (char *) (_currentFile + 1), _currentFile->nameLength);
+	
+	for (int r = 0; r < (int) strlen(name); r++) {
+		if (name[r] == '/') name[r] = '\\';
+	}
+
+	name[_currentFile->nameLength] = 0;
+	
+	if (name[strlen(name) - 1] == '\\') {
+		name[strlen(name) - 1] = 0;
+	}	
+}
+
+bool ZipFile::skipFile() {
+	bool valid;
+
+	do {
+	
+		// Move on to the next file
+		_currentFile = (FileHeader *) (
+			((char *) (_currentFile)) + sizeof(*_currentFile) + _currentFile->nameLength + _currentFile->fileSize + _currentFile->extraLength
+		);
+		
+			// Return true if there are more files.  Check this by looking for the magic number
+		valid =  (_currentFile->magic[0] == 0x50) &&
+				(_currentFile->magic[1] == 0x4B) &&
+				(_currentFile->magic[2] == 0x03) &&
+				(_currentFile->magic[3] == 0x04);
+		
+			
+	} while (valid && !currentFileInFolder());
+	
+	return valid;
+	
+	// Currently doesn't handle data descriptors!
+}
+
+
+
+u32 ZipFile::misaligned32(u32* v) {
+	char* b = (char *) v;
+	return (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];
+}
+
+u16 ZipFile::misaligned16(u16* v) {
+	char* b = (char *) v;
+	return (b[0] << 8) + b[1];
+}
+
+int ZipFile::getFileSize() {
+	return _currentFile->fileSize;
+}
+
+bool ZipFile::isDirectory() {
+	return _currentFile->fileSize == 0; 		// This is a bit wrong, but seems to work.
+}
+
+char* ZipFile::getFile() {
+	return ((char *) (_currentFile)) + sizeof(*_currentFile) + _currentFile->nameLength + _currentFile->extraLength;
+}
+
+bool ZipFile::findFile(char* search) {
+	changeToRoot();
+	restartFile();
+	
+	char searchName[128];
+	strcpy(searchName, search);
+	for (int r = 0; r < (int) strlen(searchName); r++) {
+		if (searchName[r] == '/') searchName[r] = '\\';
+	}
+
+	if (*(searchName + strlen(searchName) - 1) == '\\') {	// Directories have a terminating slash
+		*(searchName + strlen(searchName) - 1) = '\0';		// which we need to dispose of.
+	}
+
+	
+	do {
+		char name[128];
+		getFileName(name);
+		if (*(name + strlen(name) - 1) == '\\') {	// Directories have a terminating slash
+			*(name + strlen(name) - 1) = '\0';		// which we need to dispose of.
+		}
+		
+		
+		if (!stricmp(name, searchName)) {
+//			consolePrintf("'%s'=='%s'\n", name, searchName);
+			return true;		// Got it!
+		} else {
+//			consolePrintf("'%s'!='%s'\n", name, searchName);
+		}
+	} while (skipFile());
+
+	return false;		// File wasn't found
+}
+
+void ZipFile::changeToRoot() {
+	_directory[0] = 0;
+}
+
+void ZipFile::changeDirectory(char* dir) {
+//	consolePrintf("Current dir now '%s'\n", dir);
+	strcpy(_directory, dir);
+}
+
+ZipFile::~ZipFile() {
+
+}
+/* Zip File Reader
+ * Copyright (C) 2002-2004 Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 
+ */
+
+
+#include "stdafx.h"
+#include "zipreader.h"
+
+#define SWAP_U16(v) (((v & 0xFF) << 8) + (v & 0xFF00))
+#define SWAP_U32(v) ((SWAP_U16((v & 0XFFFF0000) >> 16) + (SWAP_U16(v & 0x0000FFFF) << 16)))
+
+
+ZipFile::ZipFile() {
+	// Locate a zip file in cartridge memory space
+	
+	consolePrintf("ZIP file check...");
+	
+	char* p = (char *) ZF_SEARCH_START;
+	bool found = false;
+	
+	_zipFile = NULL;
+	
+	while ((p != (char *) ZF_SEARCH_END) && (!found)) {
+		// Zip file header is: 0x504B0304
+		
+		if ( (*p == 0x50) && (*(p + 1) == 0x4B) && (*(p + 2) == 0x03) && (*(p + 3) == 0x04) ) {
+			// Found header!
+			found = true;
+			_zipFile = p;
+		}
+	
+		if (!found) p += ZF_SEARCH_STRIDE;
+		
+	}
+
+	if (_zipFile) {
+		consolePrintf("Ok!\n");
+	} else {
+		consolePrintf("Not in use!\n");
+		return;
+	}
+	
+	changeToRoot();
+	restartFile();
+	
+	if (_currentFile->compSize != (u32) getFileSize()) {
+		consolePrintf("Error: ZIP file contains compression!\n");
+	}
+	
+	_allFilesVisible = false;
+}
+
+bool ZipFile::isReady() {
+	return _zipFile != NULL;
+}
+
+bool ZipFile::restartFile() {
+	_currentFile = (FileHeader *) _zipFile;
+	char name[128];
+	getFileName(name);
+
+	bool more = true;
+
+	while (!currentFileInFolder() && more) {
+		char name[128];
+		getFileName(name);
+		more = skipFile();
+	}
+	
+	return more;
+}
+
+bool ZipFile::currentFileInFolder() {
+	char name[128];
+	
+	if (_allFilesVisible) return true;
+	
+	getFileName(name);
+	
+	if (_directory[0] == 0) { // Root directory
+		name[strlen(name) - 1] = 0;
+		return !strchr(name, '\\'); 	// Not in root if contains a / character before the last character
+	} else {
+/*		if (name starts with directory && it's not the directory
+			&& (no slashes after the directory || it's the last character)
+			&& (slash follows directory)
+	*/
+		if ((strstr(name, _directory) == name) && (strlen(name) != strlen(_directory))	
+			&& ((strchr(name + strlen(_directory) + 1, '\\') == NULL)
+			|| (strchr(name + strlen(_directory) + 1, '\\') == name + strlen(name) - 1))
+			&& (*(name + strlen(_directory)) == '\\')) {
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+void ZipFile::getFileName(char* name) {
+	strncpy(name, (char *) (_currentFile + 1), _currentFile->nameLength);
+	
+	for (int r = 0; r < (int) strlen(name); r++) {
+		if (name[r] == '/') name[r] = '\\';
+	}
+
+	name[_currentFile->nameLength] = 0;
+	
+	if (name[strlen(name) - 1] == '\\') {
+		name[strlen(name) - 1] = 0;
+	}	
+}
+
+bool ZipFile::skipFile() {
+	bool valid;
+
+	do {
+	
+		// Move on to the next file
+		_currentFile = (FileHeader *) (
+			((char *) (_currentFile)) + sizeof(*_currentFile) + _currentFile->nameLength + _currentFile->fileSize + _currentFile->extraLength
+		);
+		
+			// Return true if there are more files.  Check this by looking for the magic number
+		valid =  (_currentFile->magic[0] == 0x50) &&
+				(_currentFile->magic[1] == 0x4B) &&
+				(_currentFile->magic[2] == 0x03) &&
+				(_currentFile->magic[3] == 0x04);
+		
+			
+	} while (valid && !currentFileInFolder());
+	
+	return valid;
+	
+	// Currently doesn't handle data descriptors!
+}
+
+
+
+u32 ZipFile::misaligned32(u32* v) {
+	char* b = (char *) v;
+	return (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];
+}
+
+u16 ZipFile::misaligned16(u16* v) {
+	char* b = (char *) v;
+	return (b[0] << 8) + b[1];
+}
+
+int ZipFile::getFileSize() {
+	return _currentFile->fileSize;
+}
+
+bool ZipFile::isDirectory() {
+	return _currentFile->fileSize == 0; 		// This is a bit wrong, but seems to work.
+}
+
+char* ZipFile::getFile() {
+	return ((char *) (_currentFile)) + sizeof(*_currentFile) + _currentFile->nameLength + _currentFile->extraLength;
+}
+
+bool ZipFile::findFile(char* search) {
+	changeToRoot();
+	restartFile();
+	
+	char searchName[128];
+	strcpy(searchName, search);
+	for (int r = 0; r < (int) strlen(searchName); r++) {
+		if (searchName[r] == '/') searchName[r] = '\\';
+	}
+
+	if (*(searchName + strlen(searchName) - 1) == '\\') {	// Directories have a terminating slash
+		*(searchName + strlen(searchName) - 1) = '\0';		// which we need to dispose of.
+	}
+
+	
+	do {
+		char name[128];
+		getFileName(name);
+		if (*(name + strlen(name) - 1) == '\\') {	// Directories have a terminating slash
+			*(name + strlen(name) - 1) = '\0';		// which we need to dispose of.
+		}
+		
+		
+		if (!stricmp(name, searchName)) {
+//			consolePrintf("'%s'=='%s'\n", name, searchName);
+			return true;		// Got it!
+		} else {
+//			consolePrintf("'%s'!='%s'\n", name, searchName);
+		}
+	} while (skipFile());
+
+	return false;		// File wasn't found
+}
+
+void ZipFile::changeToRoot() {
+	_directory[0] = 0;
+}
+
+void ZipFile::changeDirectory(char* dir) {
+//	consolePrintf("Current dir now '%s'\n", dir);
+	strcpy(_directory, dir);
+}
+
+ZipFile::~ZipFile() {
+
+}


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/zipreader.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/arm9/source/zipreader.h
===================================================================
--- scummvm/trunk/backends/platform/ds/arm9/source/zipreader.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/arm9/source/zipreader.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,162 @@
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _ZIPREADER_H_
+#define _ZIPREADER_H_
+#include "stdafx.h"
+#include "portdefs.h"
+#define ZF_SEARCH_START 0x08000000
+#define ZF_SEARCH_END 0x09000000
+#define ZF_SEARCH_STRIDE 16
+
+class ZipFile {
+
+	struct FileHeader {
+		char magic[4];		// Header (0x04034B50)			0
+		u16 minVersion;		// Version needed to extract	4
+		u16 flags;			// Flags						6
+		u16 comp;			// Compression method			8
+		u16 modTime;		// Last modified file time		A
+		u16 modDate;		// Last modified file data		C
+		u32 crc32;			// CRC32						F
+		u32 compSize;		// Compressed size
+		u32 fileSize;		// Uncompressed file size
+		u16 nameLength;		// Length of the filename
+		u16 extraLength;	// Length of any extra data
+	} __attribute__ ((packed));
+
+	char* _zipFile;
+	char _directory[128];
+	
+	bool _allFilesVisible;
+	
+	FileHeader* _currentFile;
+
+public:
+	ZipFile();
+	~ZipFile();
+
+	bool isReady();
+	
+	// These operations set the current file
+	bool restartFile();
+	bool skipFile();
+	bool findFile(char* search);	
+
+	// These return the file's data and information
+	char* getFile();
+	int getFileSize();
+	void getFileName(char* name);
+	bool isDirectory();
+	
+	// These set the current directory
+	void changeDirectory(char* name);
+	void changeToRoot();
+	void setAllFilesVisible(bool state) { _allFilesVisible = state; }
+	
+	bool currentFileInFolder();
+	
+	u16 misaligned16(u16* v);
+	u32 misaligned32(u32* v);
+
+};
+
+
+#endif
+/* ScummVMDS - Scumm Interpreter DS Port
+ * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+ 
+#ifndef _ZIPREADER_H_
+#define _ZIPREADER_H_
+#include "stdafx.h"
+#include "portdefs.h"
+#define ZF_SEARCH_START 0x08000000
+#define ZF_SEARCH_END 0x09000000
+#define ZF_SEARCH_STRIDE 16
+
+class ZipFile {
+
+	struct FileHeader {
+		char magic[4];		// Header (0x04034B50)			0
+		u16 minVersion;		// Version needed to extract	4
+		u16 flags;			// Flags						6
+		u16 comp;			// Compression method			8
+		u16 modTime;		// Last modified file time		A
+		u16 modDate;		// Last modified file data		C
+		u32 crc32;			// CRC32						F
+		u32 compSize;		// Compressed size
+		u32 fileSize;		// Uncompressed file size
+		u16 nameLength;		// Length of the filename
+		u16 extraLength;	// Length of any extra data
+	} __attribute__ ((packed));
+
+	char* _zipFile;
+	char _directory[128];
+	
+	bool _allFilesVisible;
+	
+	FileHeader* _currentFile;
+
+public:
+	ZipFile();
+	~ZipFile();
+
+	bool isReady();
+	
+	// These operations set the current file
+	bool restartFile();
+	bool skipFile();
+	bool findFile(char* search);	
+
+	// These return the file's data and information
+	char* getFile();
+	int getFileSize();
+	void getFileName(char* name);
+	bool isDirectory();
+	
+	// These set the current directory
+	void changeDirectory(char* name);
+	void changeToRoot();
+	void setAllFilesVisible(bool state) { _allFilesVisible = state; }
+	
+	bool currentFileInFolder();
+	
+	u16 misaligned16(u16* v);
+	u32 misaligned32(u32* v);
+
+};
+
+
+#endif


Property changes on: scummvm/trunk/backends/platform/ds/arm9/source/zipreader.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
===================================================================
--- scummvm/trunk/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,186 @@
+
+#ifndef SCUMMVM_IPC_INCLUDE
+#define SCUMMVM_IPC_INCLUDE
+
+//////////////////////////////////////////////////////////////////////
+
+#include <nds/jtypes.h>
+#include <nds/ipc.h>
+
+//////////////////////////////////////////////////////////////////////
+
+ 
+typedef struct _adpcmBuffer {
+	u8* buffer[8];
+	bool filled[8];
+	u8* arm7Buffer[8];
+	bool arm7Dirty[8];
+	bool semaphore;
+} adpcmBuffer;
+ 
+//////////////////////////////////////////////////////////////////////
+
+typedef struct scummvmTransferRegion {
+  uint32 heartbeat;          // counts frames
+ 
+   int16 touchX,   touchY;   // TSC X, Y
+   int16 touchXpx, touchYpx; // TSC X, Y pixel values
+   int16 touchZ1,  touchZ2;  // TSC x-panel measurements
+  uint16 tdiode1,  tdiode2;  // TSC temperature diodes
+  uint32 temperature;        // TSC computed temperature
+ 
+  uint16 buttons;            // X, Y, /PENIRQ buttons
+ 
+  union {
+    uint8 curtime[8];        // current time response from RTC
+ 
+    struct {
+      u8 rtc_command;
+      u8 rtc_year;           //add 2000 to get 4 digit year
+      u8 rtc_month;          //1 to 12
+      u8 rtc_day;            //1 to (days in month)
+ 
+      u8 rtc_incr;
+      u8 rtc_hours;          //0 to 11 for AM, 52 to 63 for PM
+      u8 rtc_minutes;        //0 to 59
+      u8 rtc_seconds;        //0 to 59
+    };
+  };
+ 
+  uint16 battery;            // battery life ??  hopefully.  :)
+  uint16 aux;                // i have no idea...
+ 
+  pTransferSound soundData;
+  
+  adpcmBuffer adpcm;
+  
+ 
+  // Don't rely on these below, will change or be removed in the future
+  vuint32 mailAddr;
+  vuint32 mailData;
+  vuint8 mailRead;
+  vuint8 mailBusy;
+  vuint32 mailSize;
+  
+  bool performArm9SleepMode;
+  
+  u32 test;
+  int tweak;
+  bool tweakChanged;
+  
+//  bool fillSoundFirstHalf;
+//  bool fillSoundSecondHalf;
+
+  // These are used for ScummVMs sound output
+  bool fillNeeded[4];
+  int playingSection;
+  
+  bool reset;
+  
+  // Streaming sound
+  bool streamFillNeeded[4];
+  int streamPlayingSection;
+} scummTransferRegion, * pscummTransferRegion;
+
+//////////////////////////////////////////////////////////////////////
+
+#undef IPC
+#define IPC ((scummTransferRegion volatile *)(0x027FF000))
+
+
+#endif
+
+
+
+#ifndef SCUMMVM_IPC_INCLUDE
+#define SCUMMVM_IPC_INCLUDE
+
+//////////////////////////////////////////////////////////////////////
+
+#include <nds/jtypes.h>
+#include <nds/ipc.h>
+
+//////////////////////////////////////////////////////////////////////
+
+ 
+typedef struct _adpcmBuffer {
+	u8* buffer[8];
+	bool filled[8];
+	u8* arm7Buffer[8];
+	bool arm7Dirty[8];
+	bool semaphore;
+} adpcmBuffer;
+ 
+//////////////////////////////////////////////////////////////////////
+
+typedef struct scummvmTransferRegion {
+  uint32 heartbeat;          // counts frames
+ 
+   int16 touchX,   touchY;   // TSC X, Y
+   int16 touchXpx, touchYpx; // TSC X, Y pixel values
+   int16 touchZ1,  touchZ2;  // TSC x-panel measurements
+  uint16 tdiode1,  tdiode2;  // TSC temperature diodes
+  uint32 temperature;        // TSC computed temperature
+ 
+  uint16 buttons;            // X, Y, /PENIRQ buttons
+ 
+  union {
+    uint8 curtime[8];        // current time response from RTC
+ 
+    struct {
+      u8 rtc_command;
+      u8 rtc_year;           //add 2000 to get 4 digit year
+      u8 rtc_month;          //1 to 12
+      u8 rtc_day;            //1 to (days in month)
+ 
+      u8 rtc_incr;
+      u8 rtc_hours;          //0 to 11 for AM, 52 to 63 for PM
+      u8 rtc_minutes;        //0 to 59
+      u8 rtc_seconds;        //0 to 59
+    };
+  };
+ 
+  uint16 battery;            // battery life ??  hopefully.  :)
+  uint16 aux;                // i have no idea...
+ 
+  pTransferSound soundData;
+  
+  adpcmBuffer adpcm;
+  
+ 
+  // Don't rely on these below, will change or be removed in the future
+  vuint32 mailAddr;
+  vuint32 mailData;
+  vuint8 mailRead;
+  vuint8 mailBusy;
+  vuint32 mailSize;
+  
+  bool performArm9SleepMode;
+  
+  u32 test;
+  int tweak;
+  bool tweakChanged;
+  
+//  bool fillSoundFirstHalf;
+//  bool fillSoundSecondHalf;
+
+  // These are used for ScummVMs sound output
+  bool fillNeeded[4];
+  int playingSection;
+  
+  bool reset;
+  
+  // Streaming sound
+  bool streamFillNeeded[4];
+  int streamPlayingSection;
+} scummTransferRegion, * pscummTransferRegion;
+
+//////////////////////////////////////////////////////////////////////
+
+#undef IPC
+#define IPC ((scummTransferRegion volatile *)(0x027FF000))
+
+
+#endif
+
+


Property changes on: scummvm/trunk/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/backends/platform/ds/makefile
===================================================================
--- scummvm/trunk/backends/platform/ds/makefile	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/backends/platform/ds/makefile	2006-07-09 11:47:17 UTC (rev 23452)
@@ -0,0 +1,42 @@
+#SUBDIRS:= `ls | egrep -v '^(CVS|tools)$$'`
+
+
+
+
+export PATH	:=	$(DEVKITARM)/bin:$(PATH)
+
+export portdir = $(CURDIR)/arm9
+export srcdir = $(CURDIR)/../../..
+
+
+SUBDIRS := arm7 arm9
+
+all:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i; fi; done;
+clean:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i clean; fi; done;
+
+export:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i export; fi; done;
+
+#SUBDIRS:= `ls | egrep -v '^(CVS|tools)$$'`
+
+
+
+
+export PATH	:=	$(DEVKITARM)/bin:$(PATH)
+
+export portdir = $(CURDIR)/arm9
+export srcdir = $(CURDIR)/../../..
+
+
+SUBDIRS := arm7 arm9
+
+all:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i; fi; done;
+clean:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i clean; fi; done;
+
+export:
+	@for i in $(SUBDIRS); do if test -d $$i; then make -C $$i export; fi; done;
+

Modified: scummvm/trunk/common/scummsys.h
===================================================================
--- scummvm/trunk/common/scummsys.h	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/common/scummsys.h	2006-07-09 11:47:17 UTC (rev 23452)
@@ -320,6 +320,33 @@
 	typedef unsigned long int uint32;
 	typedef signed long int int32;
 
+#elif defined (__DS__) //NeilM
+	#define CDECL 
+	#define SCUMM_NEED_ALIGNMENT
+	#define SCUMM_LITTLE_ENDIAN 
+
+	#define scumm_stricmp stricmp
+	#define scumm_strnicmp strnicmp
+	#define CHECK_HEAP
+
+	#define FORCEINLINE inline
+	#define NORETURN __attribute__((__noreturn__))
+	#define GCC_PACK __attribute__((packed))
+	#define _HEAPOK 0
+
+	#include "nds/jtypes.h"
+	#include <stdarg.h>
+	#include <ctype.h>
+	#include <string.h>
+	#include <math.h>
+    #include <time.h>
+
+	#define START_PACK_STRUCTS pack (push, 1)
+	#define END_PACK_STRUCTS	 pack(pop)
+	
+	#define STRINGBUFLEN 256
+	#define SCUMM_LITTLE_ENDIAN 
+
 #elif defined(_WIN32_WCE)
 
 	#define scumm_stricmp stricmp
@@ -356,7 +383,6 @@
 	#endif
 
 #else
-
 	#error No system type defined
 
 #endif

Modified: scummvm/trunk/engines/scumm/dialogs.cpp
===================================================================
--- scummvm/trunk/engines/scumm/dialogs.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/engines/scumm/dialogs.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -27,6 +27,10 @@
 
 #include "graphics/scaler.h"
 
+#ifdef __DS__
+#include "scummhelp.h"
+#endif
+
 #include "gui/about.h"
 #include "gui/chooser.h"
 #include "gui/eval.h"
@@ -710,7 +714,12 @@
 
 	String titleStr, *keyStr, *dscStr;
 
+#ifndef __DS__
 	ScummHelp::updateStrings(_game.id, _game.version, _game.platform, _page, titleStr, keyStr, dscStr);
+#else
+	// DS version has a different help screen
+	DS::updateStrings(_game.id, _game.version, _game.platform, _page, titleStr, keyStr, dscStr);
+#endif
 
 	_title->setLabel(titleStr);
 	for (int i = 0; i < HELP_NUM_LINES; i++) {

Modified: scummvm/trunk/engines/scumm/gfx.cpp
===================================================================
--- scummvm/trunk/engines/scumm/gfx.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/engines/scumm/gfx.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -32,6 +32,9 @@
 #include "scumm/resource.h"
 #include "scumm/usage_bits.h"
 #include "scumm/he/wiz_he.h"
+#ifdef __DS__
+#include "blitters.h"
+#endif
 
 namespace Scumm {
 
@@ -545,6 +548,9 @@
 		// Handle the text mask in older games; newer (V7/V8) games do not use it anymore.
 		const byte *text = (byte *)_charset->_textSurface.pixels + x + y * _charset->_textSurface.pitch;
 	
+#ifdef __DS__
+		DS::asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, _screenWidth, _charset->_textSurface.pitch);
+#else	
 		// Compose the text over the game graphics
 		for (int h = 0; h < height; ++h) {
 			for (int w = 0; w < width; ++w) {
@@ -557,6 +563,7 @@
 			dst += _screenWidth;
 			text += _charset->_textSurface.pitch;
 		}
+#endif
 	} else {
 		// Just do a simple blit in V7/V8 games.
 		blit(dst, _screenWidth, src, vs->pitch, width, height);
@@ -974,6 +981,10 @@
 }
 
 static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) {
+
+#ifndef __DS__
+	
+	
 	do {
 #if defined(SCUMM_NEED_ALIGNMENT)
 		memcpy(dst, src, 8);
@@ -984,6 +995,10 @@
 		dst += dstPitch;
 		src += dstPitch;
 	} while (--height);
+#else	
+	DS::asmCopy8Col(dst, dstPitch, src, height);
+#endif
+	
 }
 
 static void clear8Col(byte *dst, int dstPitch, int height) {

Modified: scummvm/trunk/engines/scumm/thumbnail.cpp
===================================================================
--- scummvm/trunk/engines/scumm/thumbnail.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/engines/scumm/thumbnail.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -104,7 +104,7 @@
 void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
 	Graphics::Surface thumb;
 
-#ifndef PALMOS_68K
+#if !defined(PALMOS_68K) || !defined(__DS__)
 	if (!createThumbnailFromScreen(&thumb))
 #endif
 		thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));

Modified: scummvm/trunk/gui/options.cpp
===================================================================
--- scummvm/trunk/gui/options.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/gui/options.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -37,7 +37,7 @@
 #include "sound/mididrv.h"
 #include "sound/mixer.h"
 
-#if (!( defined(PALMOS_MODE) || defined(__DC__) || defined(__GP32__) || defined(__amigaos4__) ) && !defined(_MSC_VER))
+#if (!( defined(PALMOS_MODE) || defined(__DC__) || defined(__GP32__) || defined(__amigaos4__) ) && !defined(_MSC_VER) && !defined(__DS__))
 #include <sys/param.h>
 #include <unistd.h>
 #endif

Modified: scummvm/trunk/sound/fmopl.cpp
===================================================================
--- scummvm/trunk/sound/fmopl.cpp	2006-07-09 11:47:00 UTC (rev 23451)
+++ scummvm/trunk/sound/fmopl.cpp	2006-07-09 11:47:17 UTC (rev 23452)
@@ -35,7 +35,7 @@
 
 #include "common/util.h"
 
-#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (__MAEMO__)
+#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (__MAEMO__) || defined(__DS__)
 #include "common/config-manager.h"
 #endif
 
@@ -1172,7 +1172,7 @@
 	// We need to emulate one YM3812 chip
 	int env_bits = FMOPL_ENV_BITS_HQ;
 	int eg_ent = FMOPL_EG_ENT_HQ;
-#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(__MAEMO__)
+#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(__MAEMO__) || defined(__DS__)
 	if (ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) {
 		env_bits = FMOPL_ENV_BITS_HQ;
 		eg_ent = FMOPL_EG_ENT_HQ;






More information about the Scummvm-git-logs mailing list