diff options
author | Max Horn | 2006-07-06 21:44:48 +0000 |
---|---|---|
committer | Max Horn | 2006-07-06 21:44:48 +0000 |
commit | 1d8d9f5510dc5f574e926bd6fadb9d20337daede (patch) | |
tree | 5cdcf6c8a233159776be9d90f3f39885222f65eb /backends/platform/ps2 | |
parent | 9269ebe9f5a281f452594f1e8108e31c88a398fb (diff) | |
download | scummvm-rg350-1d8d9f5510dc5f574e926bd6fadb9d20337daede.tar.gz scummvm-rg350-1d8d9f5510dc5f574e926bd6fadb9d20337daede.tar.bz2 scummvm-rg350-1d8d9f5510dc5f574e926bd6fadb9d20337daede.zip |
Moving remaining platform/backends code, as previously threatened
svn-id: r23380
Diffstat (limited to 'backends/platform/ps2')
39 files changed, 8371 insertions, 0 deletions
diff --git a/backends/platform/ps2/DmaPipe.cpp b/backends/platform/ps2/DmaPipe.cpp new file mode 100644 index 0000000000..7f3a372234 --- /dev/null +++ b/backends/platform/ps2/DmaPipe.cpp @@ -0,0 +1,301 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// minimalistic gfx pipe implementation based on Vzzrzzn's GfxPipe. + +#include <kernel.h> +#include <malloc.h> +#include "DmaPipe.h" +#include "GsDefs.h" + +class SinglePipe { +public: + SinglePipe(uint64 *buf, uint32 size); + uint32 spaceLeft(void); + void flush(void); + void setGifRegListTag(uint8 numRegs, uint64 list); + void setGifLoopTag(uint16 nLoop); + void setReg(uint64 reg, uint64 value); + void setListReg(uint64 value1, uint64 value2); + void appendChain(uint64 dmaTag); + void init(void); + uint64 *_chainHead; +private: + uint64 *_bufPos; + uint16 *_chainSize; + uint64 *_buf; + uint32 _size; +}; + +DmaPipe::DmaPipe(uint32 size) { + size &= ~0x1F; + _buf = (uint64*)memalign(64, size); + _curPipe = 0; + _pipes[0] = new SinglePipe(_buf, size >> 4); + _pipes[1] = new SinglePipe(_buf + (size >> 4), size >> 4); + + // reset DMAC Channel 2 + D2_CHCR = 0; + D2_TADR = 0; + D2_MADR = 0; + D2_ASR1 = 0; + D2_ASR0 = 0; + D_STAT = 0xFF1F; + D_CTRL = 0; + D_PCR = 0; + D_SQWC = 0; + D_RBOR = 0; + D_RBSR = 0; + D_CTRL = 1; + if (!(D_STAT & CIM2)) // channel 2 interrupts enabled? + D_STAT = CIM2; // enable them + if (D_STAT & CIS2) // is there an old interrupt we have to acknowledge? + D_STAT = CIS2; // do so... + SifSetDChain(); +} + +void DmaPipe::uploadTex(uint32 dest, uint16 bufWidth, uint16 destOfsX, uint16 destOfsY, uint8 pixelFmt, const void *src, uint16 width, uint16 height) { + + checkSpace(5); + *(_pipes[_curPipe]->_chainHead) &= 0xffffffff8fffffff; // change last chain tag id, from 'end' to 'cnt' + *(_pipes[_curPipe]->_chainHead) |= (1 << 28); + _pipes[_curPipe]->setGifLoopTag(4); + _pipes[_curPipe]->setReg(GPR_BITBLTBUF, GS_SET_DEST_BLTBUF((dest/256) & 0x3fff, (bufWidth/64) & 0x3f, pixelFmt & 0x3f)); + _pipes[_curPipe]->setReg( GPR_TRXPOS, GS_SET_DEST_TRXPOS(destOfsX, destOfsY)); + _pipes[_curPipe]->setReg( GPR_TRXREG, GS_SET_TRXREG(width, height)); + _pipes[_curPipe]->setReg( GPR_TRXDIR, 0); + + checkSpace(15); + uint32 numq = width * height; + switch (pixelFmt) { + case GS_PSMCT32: + numq = (numq + 3) >> 2; break; + case GS_PSMCT24: + numq = (numq + 2) / 3; break; + case GS_PSMCT16: + case GS_PSMCT16S: + numq = (numq + 7) >> 3; break; + case GS_PSMT8: + case GS_PSMT8H: + numq = (numq + 15) >> 4; break; + case GS_PSMT4HL: + case GS_PSMT4HH: + case GS_PSMT4: + numq = (numq + 31) >> 5; break; + default: + numq = 0; + } + uint64 texSrc = (uint32)src & 0x7fffffff; + while (numq) { + uint64 sendQuads = (numq <= 0x7FF0) ? numq : 0x7FF0; + _pipes[_curPipe]->appendChain((1 << 28) | 1); + _pipes[_curPipe]->appendChain(0x0800000000000000 + sendQuads); // IMAGE mode giftag. Flg = 10b, nloop = currq + _pipes[_curPipe]->appendChain((texSrc << 32) | 0x0000000030000000 | sendQuads); // set up dma tag for image transfer. next = tex addr, id = 11b, qwc = numq + numq -= sendQuads; + texSrc += sendQuads * 16; + } + _pipes[_curPipe]->appendChain(0x0000000070000000); // next dma tag + _pipes[_curPipe]->setGifLoopTag(1); + _pipes[_curPipe]->setReg(GPR_TEXFLUSH, 1); +} + +void DmaPipe::setTex(uint32 tex, uint32 texBufWidth, uint8 texPowW, uint8 texPowH, uint8 texPixFmt, uint32 clut, uint8 csm, uint32 clutBufWidth, uint32 clutPixFmt) { + checkSpace(7); + _pipes[_curPipe]->setGifLoopTag(6); + _pipes[_curPipe]->setReg( GPR_TEXCLUT, 256 / 64); + _pipes[_curPipe]->setReg(GPR_TEXFLUSH, 0); + _pipes[_curPipe]->setReg( GPR_TEXA, GS_SET_TEXA(128, 1, 0)); + _pipes[_curPipe]->setReg( GPR_TEX1_1, GS_SET_TEX1(0, 0, FILTER_LINEAR, FILTER_LINEAR, 0, 0, 0)); + _pipes[_curPipe]->setReg( GPR_TEX0_1, GS_SET_TEX0(tex / 256, texBufWidth / 64, texPixFmt, texPowW, texPowH, 1, 0, clut / 256, clutBufWidth / 64, csm, 0, 1)); + _pipes[_curPipe]->setReg( GPR_CLAMP_1, 0); +} + +void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const TexVertex *t1, const TexVertex *t2) { + checkSpace(4); + _pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff535310); + _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 1, 0, 1, 0, 1, 0, 0), + GS_SET_COLQ(GS_RGBA(0x80, 0x80, 0x80, 0x80))); + _pipes[_curPipe]->setListReg( GS_SET_UV(t1->u, t1->v), + GS_SET_XYZ(p1->x, p1->y, p1->z)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t2->u, t2->v), + GS_SET_XYZ(p2->x, p2->y, p2->z)); +} + +void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, const TexVertex *t1, const TexVertex *t2, const TexVertex *t3, const TexVertex *t4, uint32 rgba) { + checkSpace(6); + _pipes[_curPipe]->setGifRegListTag(10, 0xffffff5353535310); + + _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 1, 0, 1, 0, 1, 0, 0), + GS_SET_COLQ(rgba)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t1->u, t1->v), + GS_SET_XYZ(p1->x, p1->y, p1->z)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t2->u, t2->v), + GS_SET_XYZ(p2->x, p2->y, p2->z)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t3->u, t3->v), + GS_SET_XYZ(p3->x, p3->y, p3->z)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t4->u, t4->v), + GS_SET_XYZ(p4->x, p4->y, p4->z)); +} + +void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, uint32 rgba) { + checkSpace(4); + _pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff555510); + _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 0, 0, 0, 0, 0), + GS_SET_COLQ(rgba)); + _pipes[_curPipe]->setListReg( GS_SET_XYZ(p1->x, p1->y, p1->z), + GS_SET_XYZ(p2->x, p2->y, p2->z)); + _pipes[_curPipe]->setListReg( GS_SET_XYZ(p3->x, p3->y, p3->z), + GS_SET_XYZ(p4->x, p4->y, p4->z)); +} + +void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, uint32 rgba) { + checkSpace(3); + _pipes[_curPipe]->setGifRegListTag( 4, 0xffffffffffff5510); + _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 0, 0, 1, 0, 0, 0, 0), + GS_SET_COLQ(rgba)); + _pipes[_curPipe]->setListReg( GS_SET_XYZ(p1->x, p1->y, p1->z), + GS_SET_XYZ(p2->x, p2->y, p2->z)); +} + +void DmaPipe::setOrigin(uint16 x, uint16 y) { + checkSpace(2); + _pipes[_curPipe]->setGifLoopTag(1); + _pipes[_curPipe]->setReg( GPR_XYOFFSET_1, GS_SET_XYOFFSET(x, y)); +} + +void DmaPipe::setAlphaBlend(AlphaBlendColor a, AlphaBlendColor b, AlphaBlendAlpha c, AlphaBlendColor d, uint8 fix) { + checkSpace(2); + _pipes[_curPipe]->setGifLoopTag(1); + _pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(a, b, c, d, fix)); +} + +void DmaPipe::setConfig(uint8 prModeCont, uint8 dither, uint8 colClamp) { + checkSpace(9); + _pipes[_curPipe]->setGifLoopTag(8); + + // set some defaults + // alpha blending formula: (A-B) * C + D + // set: A = dest pixel, b = 0, C = source alpha, D = source pixel, fix = don't care + + _pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0)); + _pipes[_curPipe]->setReg( GPR_PRIM, 0); + _pipes[_curPipe]->setReg( GPR_PABE, 0); // alpha blending off + _pipes[_curPipe]->setReg( GPR_TEST_1, GS_SET_TEST(0, 0, 0, 0, 0, 0, 1, 1)); // ztest off + _pipes[_curPipe]->setReg( GPR_ZBUF_1, (uint64)1 << 32); // zbuffer off + + _pipes[_curPipe]->setReg( GPR_PRMODECONT, prModeCont & 1); + _pipes[_curPipe]->setReg( GPR_DTHE, dither & 1); + _pipes[_curPipe]->setReg( GPR_COLCLAMP, colClamp & 1); +} + +void DmaPipe::setScissorRect(uint64 x1, uint64 y1, uint64 x2, uint64 y2) { + checkSpace(2); + _pipes[_curPipe]->setGifLoopTag(1); + _pipes[_curPipe]->setReg( GPR_SCISSOR_1, GS_SET_SCISSOR(x1, x2, y1, y2)); +} + +void DmaPipe::setDrawBuffer(uint64 base, uint64 width, uint8 pixelFmt, uint64 mask) { + checkSpace(2); + _pipes[_curPipe]->setGifLoopTag(1); + _pipes[_curPipe]->setReg( GPR_FRAME_1, GS_SET_FRAME(base / 8192, width / 64, pixelFmt, mask)); +} + +void DmaPipe::setFinishEvent(void) { + checkSpace(3); + // make GS generate a FINISH interrupt when it's done. + _pipes[_curPipe]->setGifLoopTag(2); + _pipes[_curPipe]->setReg( GPR_FINISH, 1); + _pipes[_curPipe]->setReg( GPR_SIGNAL, 1); +} + +void DmaPipe::checkSpace(uint32 needed) { + if (_pipes[_curPipe]->spaceLeft() < (needed << 1)) + flush(); +} + +void DmaPipe::waitForDma(void) { + while (D2_CHCR & 0x100) {} +} + +void DmaPipe::flush(void) { + waitForDma(); + FlushCache(0); + _pipes[_curPipe]->flush(); + _curPipe ^= 1; + _pipes[_curPipe]->init(); +} + +SinglePipe::SinglePipe(uint64 *buf, uint32 size) { + _buf = buf; + _size = size; + init(); +} + +void SinglePipe::flush(void) { + D2_TADR = (uint32)_buf; + D2_QWC = 0; + D2_CHCR |= 0x185; +} + +void SinglePipe::init(void) { + _buf[0] = 0x0000000070000000; + _buf[1] = 0; + _chainHead = _buf; + _chainSize = (uint16*)_chainHead; + _bufPos = _buf + 2; +} + +uint32 SinglePipe::spaceLeft(void) { + return (_size - (_bufPos - _buf)); +} + +void SinglePipe::appendChain(uint64 dmaTag) { + _chainHead = _bufPos; + _chainHead[0] = dmaTag; + _chainHead[1] = 0; + _chainSize = (uint16*)_chainHead; + _bufPos += 2; +} + +void SinglePipe::setReg(uint64 reg, uint64 value) { + *_bufPos++ = value; + *_bufPos++ = reg; + (*_chainSize)++; +} + +void SinglePipe::setListReg(uint64 value1, uint64 value2) { + *_bufPos++ = value1; + *_bufPos++ = value2; + (*_chainSize)++; +} + +void SinglePipe::setGifRegListTag(uint8 numRegs, uint64 list) { + *_bufPos++ = GIF_SET_TAG(1, 1, 0, 0, 1, 0) | ((uint64)numRegs << 60); + *_bufPos++ = list; + (*_chainSize)++; +} + +void SinglePipe::setGifLoopTag(uint16 nLoop) { + *_bufPos++ = GIF_SET_TAG(0, 1, 0, 0, 0, 1) | nLoop; + *_bufPos++ = 0xfffffffffffffffe; + (*_chainSize)++; +} diff --git a/backends/platform/ps2/DmaPipe.h b/backends/platform/ps2/DmaPipe.h new file mode 100644 index 0000000000..5cbef0d9ff --- /dev/null +++ b/backends/platform/ps2/DmaPipe.h @@ -0,0 +1,67 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// minimalistic gfx pipe implementation based on Vzzrzzn's GfxPipe. + +#ifndef __DMAPIPE_H__ +#define __DMAPIPE_H__ + +#include "sysdefs.h" +#include "backends/ps2/GsDefs.h" + +class SinglePipe; + +struct GsVertex { + uint16 x, y, z; +}; + +struct TexVertex { + uint16 u, v; +}; + +class DmaPipe { +public: + DmaPipe(uint32 size); + void uploadTex(uint32 dest, uint16 bufWidth, uint16 destOfsX, uint16 destOfsY, uint8 pixelFmt, const void *src, uint16 width, uint16 height); + void setTex(uint32 tex, uint32 texBufWidth, uint8 texPowW, uint8 texPowH, uint8 texPixFmt, uint32 clut, uint8 csm, uint32 clutBufWidth, uint32 clutPixFmt); + void setDrawBuffer(uint64 base, uint64 width, uint8 pixelFmt, uint64 mask); + void textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, const TexVertex *t1, const TexVertex *t2, const TexVertex *t3, const TexVertex *t4, uint32 rgba); + void textureRect(const GsVertex *p1, const GsVertex *p2, const TexVertex *t1, const TexVertex *t2); + void flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, uint32 rgba); + void flatRect(const GsVertex *p1, const GsVertex *p2, uint32 rgba); + + void setOrigin(uint16 x, uint16 y); + void setConfig(uint8 prModeCont, uint8 dither, uint8 colClamp); + void setScissorRect(uint64 x1, uint64 y1, uint64 x2, uint64 y2); + void setAlphaBlend(AlphaBlendColor a, AlphaBlendColor b, AlphaBlendAlpha c, AlphaBlendColor d, uint8 fix); + void setFinishEvent(void); + void flush(void); + void waitForDma(void); +private: + void checkSpace(uint32 needed); + uint64 *_buf; + uint8 _curPipe; + SinglePipe *_pipes[2]; +}; + +#endif //__DMAPIPE_H__ + diff --git a/backends/platform/ps2/Gs2dScreen.cpp b/backends/platform/ps2/Gs2dScreen.cpp new file mode 100644 index 0000000000..7cf82ae5a0 --- /dev/null +++ b/backends/platform/ps2/Gs2dScreen.cpp @@ -0,0 +1,751 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "Gs2dScreen.h" +#include <kernel.h> +#include <malloc.h> +#include <string.h> +#include <assert.h> +#include <fileio.h> +#include <math.h> +#include "DmaPipe.h" +#include "GsDefs.h" +#include "graphics/surface.h" + +extern void *_gp; + +enum Buffers { + SCREEN = 0, + MOUSE, + TEXT, + PRINTF +}; + +#define ANIM_STACK_SIZE (1024 * 32) + +#define DEFAULT_PAL_X 175 +#define DEFAULT_PAL_Y 60 +#define DEFAULT_NTSC_X 165 +#define DEFAULT_NTSC_Y 45 +#define ORG_X 256 +#define ORG_Y 256 +#define ORIGIN_X (ORG_X << 4) +#define ORIGIN_Y (ORG_Y << 4) +#define TEX_POW 10 + +#define SCALE(x) ((x) << 4) + +#define M_SIZE 128 +#define M_POW 7 + +static volatile uint32 g_VblankCmd = 0, g_DmacCmd = 0; +static int g_VblankSema, g_DmacSema, g_AnimSema; +static bool g_RunAnim = false; +static GsVertex kFullScreen[2]; +static TexVertex kMouseTex[2] = { + { SCALE(1), SCALE(1) }, + { SCALE(M_SIZE - 1), SCALE(M_SIZE - 1) } +}; +static TexVertex kPrintTex[2] = { + { SCALE(1), SCALE(1) }, + { SCALE(320), SCALE(200) } +}; + +void sioprintf(const char *zFormat, ...); +void runAnimThread(Gs2dScreen *param); + +int vblankStartHandler(int cause) { + // start of VBlank period + if (g_VblankCmd) { // is there a new image waiting? + GS_DISPFB1 = g_VblankCmd; // show it. + g_VblankCmd = 0; + iSignalSema(g_VblankSema); + } + return 0; +} + +int dmacHandler(int channel) { + if (g_DmacCmd && (channel == 2)) { // GS DMA transfer finished, + g_VblankCmd = g_DmacCmd; // we want to show the image + g_DmacCmd = 0; // when the next vblank occurs + iSignalSema(g_DmacSema); + } + return 0; +} + +int vblankEndHandler(int cause) { + if (g_RunAnim) + iSignalSema(g_AnimSema); + return 0; +} + +void createAnimThread(Gs2dScreen *screen); + +Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { + + _systemQuit = false; + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + g_VblankSema = CreateSema(&newSema); + g_DmacSema = CreateSema(&newSema); + _screenSema = CreateSema(&newSema); + newSema.init_count = 0; + newSema.max_count = 255; + g_AnimSema = CreateSema(&newSema); + assert((g_VblankSema >= 0) && (g_DmacSema >= 0) && (_screenSema >= 0) && (g_AnimSema >= 0)); + + _vblankStartId = AddIntcHandler(INT_VBLANK_START, vblankStartHandler, 0); + _vblankEndId = AddIntcHandler(INT_VBLANK_END, vblankEndHandler, 0); + _dmacId = AddDmacHandler(2, dmacHandler, 0); + + _dmaPipe = new DmaPipe(0x2000); + + EnableIntc(INT_VBLANK_START); + EnableIntc(INT_VBLANK_END); + EnableDmac(2); + + _width = width; + _height = height; + _pitch = (width + 127) & ~127; + + _screenBuf = (uint8*)memalign(64, _width * _height); + _overlayBuf = (uint16*)memalign(64, _width * _height * 2); + _clut = (uint32*)memalign(64, 256 * 4); + + memset(_screenBuf, 0, _width * _height); + memset(_clut, 0, 256 * sizeof(uint32)); + _clut[1] = GS_RGBA(0xC0, 0xC0, 0xC0, 0); + clearOverlay(); + + if (tvMode == TV_DONT_CARE) { + if (PAL_NTSC_FLAG == 'E') + _videoMode = TV_PAL; + else + _videoMode = TV_NTSC; + } else + _videoMode = tvMode; + + printf("Setting up %s mode\n", (_videoMode == TV_PAL) ? "PAL" : "NTSC"); + + // set screen size, 640x544 for pal, 640x448 for ntsc + _tvWidth = 640; + _tvHeight = ((_videoMode == TV_PAL) ? 544 : 448); + kFullScreen[0].z = kFullScreen[1].z = 0; + kFullScreen[0].x = ORIGIN_X; + kFullScreen[0].y = ORIGIN_Y; + kFullScreen[1].x = SCALE(_tvWidth) + ORIGIN_X; + kFullScreen[1].y = SCALE(_tvHeight) + ORIGIN_Y; + _blitCoords[0] = kFullScreen[0]; + _blitCoords[1] = kFullScreen[1]; + _texCoords[0].u = SCALE(1); + _texCoords[0].v = SCALE(1); + _texCoords[1].u = SCALE(_width); + _texCoords[1].v = SCALE(_height); + + uint32 tvFrameSize = _tvWidth * _tvHeight * 4; // 32 bits per pixel + + // setup frame buffer pointers + _frameBufPtr[0] = 0; + _frameBufPtr[1] = tvFrameSize; + _clutPtrs[SCREEN] = tvFrameSize * 2; + _clutPtrs[MOUSE] = _clutPtrs[SCREEN] + 0x1000; // the cluts in PSMCT32 take up half a memory page each + _clutPtrs[TEXT] = _clutPtrs[SCREEN] + 0x2000; + _texPtrs[SCREEN] = _clutPtrs[SCREEN] + 0x3000; + _texPtrs[TEXT] = 0; // these buffers are stored in the alpha gaps of the frame buffers + _texPtrs[MOUSE] = 128 * 256 * 4; + _texPtrs[PRINTF] = _texPtrs[MOUSE] + M_SIZE * M_SIZE * 4; + + _showOverlay = false; + _showMouse = false; + _mouseScaleX = (_tvWidth << 8) / _width; + _mouseScaleY = (_tvHeight << 8) / _height; + setMouseXy(_width / 2, _height / 2); + _mTraCol = 255; + _shakePos = 0; + + // setup hardware now. + GS_CSR = CSR_RESET; // Reset GS + asm ("sync.p"); + GS_CSR = 0; + GsPutIMR(0x7F00); + + uint16 dispPosX, dispPosY; + + if (_videoMode == TV_PAL) { + SetGsCrt(GS_INTERLACED, 3, 0); + dispPosX = DEFAULT_PAL_X; + dispPosY = DEFAULT_PAL_Y; + } else { + SetGsCrt(GS_INTERLACED, 2, 0); + dispPosX = DEFAULT_NTSC_X; + dispPosY = DEFAULT_NTSC_Y; + } + + asm("di"); + GS_PMODE = GS_SET_PMODE(1, 0, 1, 1, 0, 255); + GS_BGCOLOUR = GS_RGBA(0, 0, 0, 0); + GS_DISPLAY1 = GS_SET_DISPLAY(_tvWidth, _tvHeight, dispPosX, dispPosY); + asm("ei"); + + _curDrawBuf = 0; + + _dmaPipe->setOrigin(ORIGIN_X, ORIGIN_Y); + _dmaPipe->setConfig(1, 0, 1); + _dmaPipe->setScissorRect(0, 0, _tvWidth - 1, _tvHeight - 1); + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + _dmaPipe->flush(); + + _clutChanged = _screenChanged = _overlayChanged = true; + + clearPrintfOverlay(); + updateScreen(); + + createAnimTextures(); + + // create anim thread + ee_thread_t animThread, thisThread; + ReferThreadStatus(GetThreadId(), &thisThread); + + _animStack = malloc(ANIM_STACK_SIZE); + animThread.initial_priority = thisThread.current_priority - 3; + animThread.stack = _animStack; + animThread.stack_size = ANIM_STACK_SIZE; + animThread.func = (void *)runAnimThread; + animThread.gp_reg = &_gp; + + _animTid = CreateThread(&animThread); + assert(_animTid >= 0); + StartThread(_animTid, this); +} + +void Gs2dScreen::quit(void) { + _systemQuit = true; + ee_thread_t statAnim; + do { // wait until thread called ExitThread() + SignalSema(g_AnimSema); + ReferThreadStatus(_animTid, &statAnim); + } while (statAnim.status != 0x10); + DeleteThread(_animTid); + free(_animStack); + _dmaPipe->waitForDma(); // wait for dmac and vblank for the last time + while (g_DmacCmd || g_VblankCmd); + + sioprintf("kill handlers"); + DisableIntc(INT_VBLANK_START); + DisableIntc(INT_VBLANK_END); + DisableDmac(2); + RemoveIntcHandler(INT_VBLANK_START, _vblankStartId); + RemoveIntcHandler(INT_VBLANK_END, _vblankEndId); + RemoveDmacHandler(2, _dmacId); + + DeleteSema(g_VblankSema); + DeleteSema(g_DmacSema); + DeleteSema(g_AnimSema); +} + +void Gs2dScreen::createAnimTextures(void) { + uint8 *buf = (uint8*)memalign(64, 16 * 64); + memset(buf, 0, 16 * 64); + uint32 vramDest = _texPtrs[TEXT]; + for (int i = 0; i < 16; i++) { + uint32 *destPos = (uint32*)buf; + for (int ch = 15; ch >= 0; ch--) { + uint32 *src = (uint32*)(_binaryData + ((_binaryPattern[i] >> ch) & 1) * 4 * 14); + for (int line = 0; line < 14; line++) + destPos[line << 4] = src[line]; + destPos++; + } + if (!(i & 1)) + _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HH, buf, 128, 16); + else { + _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HL, buf, 128, 16); + vramDest += 128 * 16 * 4; + } + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + } + _dmaPipe->uploadTex(_clutPtrs[TEXT], 64, 0, 0, GS_PSMCT32, _binaryClut, 8, 2); + _dmaPipe->flush(); + free(buf); +} + +void Gs2dScreen::newScreenSize(uint16 width, uint16 height) { + if ((width == _width) && (height == _height)) + return; + + WaitSema(g_DmacSema); + WaitSema(g_VblankSema); + + _dmaPipe->flush(); + _width = width; + _height = height; + _pitch = (width + 127) & ~127; + + // malloc new buffers + free(_screenBuf); + free(_overlayBuf); + _screenBuf = (uint8*)memalign(64, _width * _height); + _overlayBuf = (uint16*)memalign(64, _width * _height * 2); + memset(_screenBuf, 0, _width * height); + memset(_overlayBuf, 0, _width * height * 2); + memset(_clut, 0, 256 * sizeof(uint32)); + + // clear video ram + _dmaPipe->uploadTex(_clutPtrs[MOUSE], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + + _clutChanged = _screenChanged = _overlayChanged = false; + + _texCoords[1].u = SCALE(_width); + _texCoords[1].v = SCALE(_height); + _mouseScaleX = (_tvWidth << 8) / _width; + _mouseScaleY = (_tvHeight << 8) / _height; + setMouseXy(_width / 2, _height / 2); + + SignalSema(g_VblankSema); + SignalSema(g_DmacSema); +} + +void Gs2dScreen::copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w, int h) { + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + if (y < 0) { + h += y; + buf -= y * pitch; + y = 0; + } + if (x + w > _width) + w = (int)_width - x; + if (y + h > _height) + h = (int)_height - y; + + if ((w > 0) && (h > 0)) { + WaitSema(g_DmacSema); + uint8 *dest = _screenBuf + y * _width + x; + if ((w == pitch) && (pitch == _width)) + memcpy(dest, buf, w * h); + else + for (int cnt = 0; cnt < h; cnt++) { + memcpy(dest, buf, w); + buf += pitch; + dest += _width; + } + _screenChanged = true; + SignalSema(g_DmacSema); + } +} + +void Gs2dScreen::clearScreen(void) { + WaitSema(g_DmacSema); + memset(_screenBuf, 0, _width * _height); + _screenChanged = true; + SignalSema(g_DmacSema); +} + +void Gs2dScreen::setPalette(const uint32 *pal, uint8 start, uint16 num) { + assert(start + num <= 256); + + WaitSema(g_DmacSema); + for (uint16 cnt = 0; cnt < num; cnt++) { + uint16 dest = start + cnt; + dest = (dest & 0xE7) | ((dest & 0x8) << 1) | ((dest & 0x10) >> 1); // rearrange like the GS expects it + _clut[dest] = pal[cnt] & 0xFFFFFF; + } + _clutChanged = true; + SignalSema(g_DmacSema); +} + +void Gs2dScreen::grabPalette(uint32 *pal, uint8 start, uint16 num) { + assert(start + num <= 256); + for (uint16 cnt = 0; cnt < num; cnt++) { + uint16 src = start + cnt; + src = (src & 0xE7) | ((src & 0x8) << 1) | ((src & 0x10) >> 1); + pal[cnt] = _clut[src]; + } +} + +void Gs2dScreen::grabScreen(Graphics::Surface *surf) { + assert(surf); + WaitSema(g_DmacSema); + surf->create(_width, _height, 1); + memcpy(surf->pixels, _screenBuf, _width * _height); + SignalSema(g_DmacSema); +} + +void Gs2dScreen::uploadToVram(void) { + if (_clutChanged) { + _clutChanged = false; + uint32 tmp = _clut[_mTraCol]; + _clut[_mTraCol] = GS_RGBA(0, 0, 0, 0x80); // this mouse color is transparent + _dmaPipe->uploadTex(_clutPtrs[MOUSE], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + _clut[_mTraCol] = tmp; + + _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + } + + if (_showOverlay) { + if (_overlayChanged) { + _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height); + _overlayChanged = false; + } + } else { + if (_screenChanged) { + _dmaPipe->uploadTex(_texPtrs[SCREEN], _pitch, 0, 0, GS_PSMT8, _screenBuf, _width, _height); + _screenChanged = false; + } + } +} + +extern "C" void _ps2sdk_alloc_lock(void); +extern "C" void _ps2sdk_alloc_unlock(void); + +void Gs2dScreen::updateScreen(void) { + WaitSema(_screenSema); + uploadToVram(); + if (!g_RunAnim) { + _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen + + if (_showOverlay) { + _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); + } else { + _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); + } + + if (_showMouse) { + GsVertex mouseCoords[2]; + mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; + mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; + mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); + mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); + mouseCoords[0].z = mouseCoords[1].z = 0; + + _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); + } + + _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1); + +#if 0 + _ps2sdk_alloc_lock(); + uint32 heapTop = (uint32)ps2_sbrk(0); + _ps2sdk_alloc_unlock(); + if (heapTop != (uint32)-1) { + float yPos = (((float)heapTop) / (32 * 1024 * 1024)) * _tvHeight; + GsVertex bottom = { SCALE(_tvWidth - 40) + ORIGIN_X, SCALE(_tvHeight) + ORIGIN_Y, 0 }; + GsVertex top = { SCALE(_tvWidth) + ORIGIN_X, 0, 0 }; + top.y = SCALE((uint16)(_tvHeight - yPos)) + ORIGIN_Y; + _dmaPipe->flatRect(&bottom, &top, GS_RGBA(0x80, 0, 0, 0x40)); + } +#endif + + WaitSema(g_DmacSema); // wait for dma transfer, if there's one running + WaitSema(g_VblankSema); // wait if there's already an image waiting for vblank + + g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler + _dmaPipe->flush(); + _curDrawBuf ^= 1; + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + } else + _dmaPipe->flush(); + SignalSema(_screenSema); +} + +void Gs2dScreen::showOverlay(void) { + _showOverlay = true; + clearOverlay(); +} + +void Gs2dScreen::hideOverlay(void) { + _screenChanged = true; + _showOverlay = false; +} + +void Gs2dScreen::setShakePos(int shake) { + _shakePos = (shake * _mouseScaleY) >> 8; + _blitCoords[0].y = SCALE(_shakePos) + ORIGIN_Y; + _blitCoords[1].y = SCALE(_tvHeight + _shakePos) + ORIGIN_Y; +} + +void Gs2dScreen::copyPrintfOverlay(const uint8 *buf) { + assert(!((uint32)buf & 63)); + _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, buf, 320, 200); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); +} + +void Gs2dScreen::clearPrintfOverlay(void) { + uint8 *tmpBuf = (uint8*)memalign(64, 320 * 200); + memset(tmpBuf, 4, 320 * 200); + _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, tmpBuf, 320, 200); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + free(tmpBuf); +} + +void Gs2dScreen::copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) { + WaitSema(g_DmacSema); + _overlayChanged = true; + uint16 *dest = _overlayBuf + y * _width + x; + for (uint32 cnt = 0; cnt < h; cnt++) { + memcpy(dest, buf, w * 2); + dest += _width; + buf += pitch; + } + SignalSema(g_DmacSema); +} + +void Gs2dScreen::clearOverlay(void) { + WaitSema(g_DmacSema); + _overlayChanged = true; + // first convert our clut to 16 bit RGBA for the overlay... + uint16 palette[256]; + for (uint32 cnt = 0; cnt < 256; cnt++) { + uint32 rgba = _clut[(cnt & 0xE7) | ((cnt & 0x8) << 1) | ((cnt & 0x10) >> 1)]; + palette[cnt] = ((rgba >> 3) & 0x1F) | (((rgba >> 11) & 0x1F) << 5) | (((rgba >> 19) & 0x1F) << 10); + } + // now copy the current screen over + for (int cnt = 0; cnt < _width * _height; cnt++) + _overlayBuf[cnt] = palette[_screenBuf[cnt]]; + SignalSema(g_DmacSema); +} + +void Gs2dScreen::grabOverlay(uint16 *buf, uint16 pitch) { + uint16 *src = _overlayBuf; + for (uint32 cnt = 0; cnt < _height; cnt++) { + memcpy(buf, src, _width * 2); + buf += pitch; + src += _width; + } +} + +void Gs2dScreen::setMouseOverlay(const uint8 *buf, uint16 width, uint16 height, uint16 hotSpotX, uint16 hotSpotY, uint8 transpCol) { + assert((width <= M_SIZE) && (height <= M_SIZE)); + + _hotSpotX = hotSpotX; + _hotSpotY = hotSpotY; + if (_mTraCol != transpCol) { + _mTraCol = transpCol; + _clutChanged = true; + } + uint8 *bufCopy = (uint8*)memalign(64, M_SIZE * M_SIZE); // make a copy to align to 64 bytes + memset(bufCopy, _mTraCol, M_SIZE * M_SIZE); + for (int cnt = 0; cnt < height; cnt++) + memcpy(bufCopy + cnt * M_SIZE, buf + cnt * width, width); + + _dmaPipe->uploadTex( _texPtrs[MOUSE], M_SIZE, 0, 0, GS_PSMT8H, bufCopy, M_SIZE, M_SIZE); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); // make sure all data has been transferred when we free bufCopy + free(bufCopy); +} + +void Gs2dScreen::showMouse(bool show) { + _showMouse = show; +} + +void Gs2dScreen::setMouseXy(int16 x, int16 y) { + _mouseX = x; + _mouseY = y; +} + +uint8 Gs2dScreen::tvMode(void) { + return _videoMode; +} + +uint16 Gs2dScreen::getWidth(void) { + return _width; +} + +uint16 Gs2dScreen::getHeight(void) { + return _height; +} + +void Gs2dScreen::wantAnim(bool runIt) { + g_RunAnim = runIt; +} + +#define LINE_SPACE 20 +#define SCRL_TIME 8 +#define V 1000 +#define Z_TRANSL 65 + +void Gs2dScreen::animThread(void) { + // animate zeros and ones while game accesses memory card, etc. + g_RunAnim = false; + float yPos = 0.0; + uint8 texSta = 0; + float scrlSpeed = (_videoMode == TV_PAL) ? (_tvHeight / (SCRL_TIME * 50.0)) : (_tvHeight / (SCRL_TIME * 60.0)); + uint8 texMax = (_tvHeight / LINE_SPACE) + (ORG_Y / LINE_SPACE); + TexVertex texNodes[4] = { + { SCALE(1), SCALE(1) }, { SCALE(1), SCALE(14) }, + { SCALE(128), SCALE(1) }, { SCALE(128), SCALE(14) } + }; + float angleStep = ((2 * PI) / _tvHeight); + + while (!_systemQuit) { + do { + WaitSema(g_AnimSema); + } while ((!_systemQuit) && (!g_RunAnim)); + + if (_systemQuit) + break; + + if (PollSema(_screenSema) > 0) { // make sure no thread is currently drawing + WaitSema(g_DmacSema); // dma transfers have to be finished + WaitSema(g_VblankSema); // wait for image, if there is one... + + // redraw the engine's last frame + _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen + + if (_showOverlay) { + _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); + } else { + _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); + } + + _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1); + + if (_showMouse) { + GsVertex mouseCoords[2]; + mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; + mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; + mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); + mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); + mouseCoords[0].z = mouseCoords[1].z = 0; + + _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); + } + + _dmaPipe->setAlphaBlend(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0); + yPos -= scrlSpeed; + if (yPos <= -LINE_SPACE) { + yPos += LINE_SPACE; + texSta++; + } + + float drawY = yPos; + + for (int i = 0; i < texMax; i++) { + uint8 texIdx = (texSta + i) & 0xF; + + float x[4] = { -64.0, -64.0, 64.0, 64.0 }; + float y[4]; + y[0] = y[2] = drawY - _tvHeight / 2 - LINE_SPACE / 2; + y[1] = y[3] = y[0] + LINE_SPACE; + float z[4]; + GsVertex nodes[4]; + + float angle = PI / 2 + angleStep * drawY; + float rotSin = sinf(angle); + float rotCos = cosf(angle); + for (int coord = 0; coord < 4; coord++) { + z[coord] = rotCos * x[coord]; + x[coord] = rotSin * x[coord]; + + nodes[coord].z = 0; + nodes[coord].x = (uint16)(((V * x[coord]) / (z[coord] + V + Z_TRANSL)) * 16); + nodes[coord].y = (uint16)(((V * y[coord]) / (z[coord] + V + Z_TRANSL)) * 16); + nodes[coord].x += SCALE(_tvWidth - 80 + ORG_X); + nodes[coord].y += SCALE(_tvHeight / 2 + ORG_Y); + } + + uint32 texPtr = _texPtrs[TEXT] + 128 * 16 * 4 * (texIdx >> 1); + if (texIdx & 1) + _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + else + _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + + _dmaPipe->textureRect(nodes + 0, nodes + 1, nodes + 2, nodes + 3, + texNodes + 0, texNodes + 1, texNodes + 2, texNodes + 3, GS_RGBA(0x80, 0x80, 0x80, 0x80)); + + drawY += LINE_SPACE; + } + g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler + _dmaPipe->flush(); + _curDrawBuf ^= 1; + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + _dmaPipe->setAlphaBlend(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0); + + SignalSema(_screenSema); + } + } + ExitThread(); +} + +void runAnimThread(Gs2dScreen *param) { + param->animThread(); +} + +// data for the animated zeros and ones... +const uint8 Gs2dScreen::_binaryData[4 * 14 * 2] = { + // figure zero + 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x22, 0x22, 0x00, 0x31, 0x13, + 0x31, 0x13, 0x20, 0x02, 0x22, 0x02, 0x31, 0x13, 0x33, 0x13, 0x20, 0x02, 0x20, 0x02, + 0x31, 0x33, 0x31, 0x13, 0x20, 0x22, 0x20, 0x02, 0x31, 0x13, 0x31, 0x13, 0x00, 0x22, + 0x22, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, + // figure one + 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x20, 0x02, 0x00, 0x11, 0x33, + 0x13, 0x11, 0x22, 0x22, 0x02, 0x00, 0x11, 0x31, 0x13, 0x11, 0x00, 0x20, 0x02, 0x00, + 0x11, 0x31, 0x13, 0x11, 0x00, 0x20, 0x02, 0x00, 0x11, 0x31, 0x13, 0x11, 0x00, 0x20, + 0x02, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11 +}; + +const uint16 Gs2dScreen::_binaryPattern[16] = { + 0xD992, 0x344B, 0xA592, 0x110D, + 0x9234, 0x2326, 0x5199, 0xC8A6, + 0x4D29, 0x18B0, 0xA5AA, 0x2949, + 0x6DB3, 0xB2AA, 0x64A4, 0x3329 +}; + +const uint32 Gs2dScreen::_binaryClut[16] __attribute__((aligned(64))) = { + GS_RGBA( 0, 0, 0, 0x40), + GS_RGBA( 50, 50, 50, 0x40), + GS_RGBA( 204, 204, 0xFF, 0x40), + GS_RGBA( 140, 140, 0xFF, 0x40), + + GS_RGBA( 0, 0, 0, 0x80), // scrPrintf: transparent + GS_RGBA( 0, 0, 0, 0x20), // scrPrintf: semitransparent + GS_RGBA(0xC0, 0xC0, 0xC0, 0), // scrPrintf: red + GS_RGBA(0x16, 0x16, 0xF0, 0), // scrPrintf: blue + + GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), // unused + GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), + GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), + GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80) +}; + + diff --git a/backends/platform/ps2/Gs2dScreen.h b/backends/platform/ps2/Gs2dScreen.h new file mode 100644 index 0000000000..47438c632c --- /dev/null +++ b/backends/platform/ps2/Gs2dScreen.h @@ -0,0 +1,116 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __GS2DSCREEN_H__ +#define __GS2DSCREEN_H__ + +#include "sysdefs.h" +#include "backends/ps2/DmaPipe.h" + +enum TVMode { + TV_DONT_CARE = 0, + TV_PAL, + TV_NTSC +}; + +enum GsInterlace { + GS_NON_INTERLACED = 0, + GS_INTERLACED +}; + + +namespace Graphics { + struct Surface; +} + +class Gs2dScreen { +public: + Gs2dScreen(uint16 width, uint16 height, TVMode tvMode); + ~Gs2dScreen(void); + void newScreenSize(uint16 width, uint16 height); + uint8 tvMode(void); + uint16 getWidth(void); + uint16 getHeight(void); + + void copyPrintfOverlay(const uint8* buf); + void clearPrintfOverlay(void); + void clearScreen(void); + + void copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w, int h); + void setPalette(const uint32 *pal, uint8 start, uint16 num); + void updateScreen(void); + void grabPalette(uint32 *pal, uint8 start, uint16 num); + void grabScreen(Graphics::Surface *surf); + //- overlay routines + void copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h); + void grabOverlay(uint16 *buf, uint16 pitch); + void clearOverlay(void); + void showOverlay(void); + void hideOverlay(void); + //- mouse routines + void setMouseOverlay(const uint8 *buf, uint16 width, uint16 height, uint16 hotSpotX, uint16 hotSpotY, uint8 transpCol); + void showMouse(bool show); + void setMouseXy(int16 x, int16 y); + void setShakePos(int shake); + + void animThread(void); + void wantAnim(bool runIt); + + void quit(void); +private: + void uploadToVram(void); + void createAnimTextures(void); + + DmaPipe *_dmaPipe; + uint8 _videoMode; + uint16 _tvWidth, _tvHeight; + GsVertex _blitCoords[2]; + TexVertex _texCoords[2]; + + uint8 _curDrawBuf; + uint32 _frameBufPtr[2]; // + uint32 _clutPtrs[3]; // vram pointers + uint32 _texPtrs[4]; // + + uint16 _width, _height, _pitch; + int16 _mouseX, _mouseY, _hotSpotX, _hotSpotY; + uint32 _mouseScaleX, _mouseScaleY; + uint8 _mTraCol; + + int _shakePos; + + bool _showMouse, _showOverlay, _screenChanged, _overlayChanged, _clutChanged; + uint16 *_overlayBuf; + uint8 *_screenBuf; + uint32 *_clut; + + int _screenSema; + int _vblankStartId, _vblankEndId, _dmacId, _animTid; + void *_animStack; + volatile bool _systemQuit; + + static const uint32 _binaryClut[16]; + static const uint8 _binaryData[4 * 14 * 2]; + static const uint16 _binaryPattern[16]; +}; + +#endif // __GS2DSCREEN_H__ diff --git a/backends/platform/ps2/GsDefs.h b/backends/platform/ps2/GsDefs.h new file mode 100644 index 0000000000..65dec5e2a6 --- /dev/null +++ b/backends/platform/ps2/GsDefs.h @@ -0,0 +1,226 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __GSDEFS_H__ +#define __GSDEFS_H__ + +#include "sysdefs.h" + +// Gs2dScreen defines: + +#define PAL_NTSC_FLAG (*(volatile uint8*)0x1FC7FF52) + +#define GS_PMODE *((volatile uint64*)0x12000000) +#define GS_CSR *((volatile uint64*)0x12001000) +#define GS_DISPFB1 *((volatile uint64*)0x12000070) +#define GS_DISPLAY1 *((volatile uint64*)0x12000080) +#define GS_BGCOLOUR *((volatile uint64*)0x120000E0) + +enum GS_CSR_FIELDS { + CSR_SIGNAL = 1 << 0, + CSR_FINISH = 1 << 1, + CSR_HSYNC = 1 << 2, + CSR_VSYNC = 1 << 3, + CSR_FLUSH = 1 << 8, + CSR_RESET = 1 << 9 +}; + +#define GS_SET_PMODE(readC1, readC2, alphaSel, alphaOut, alphaBlend, alphaFixed) \ + ((readC1) | ((readC2) << 1) | ((alphaSel) << 5) | ((alphaOut) << 6) | ((alphaBlend) << 7) | ((alphaFixed) << 8)) + +#define GS_SET_DISPLAY(width, height, xpos, ypos) \ + (((uint64)(height - 1) << 44) | ((uint64)0x9FF << 32) | \ + ((((2560 + (width - 1)) / width) - 1)<<23) | \ + (ypos << 12) | (xpos * (2560 / width))) + +#define GS_SET_DISPFB(frameBufPtr, frameBufWidth, psm) \ + (((frameBufPtr) / 8192) | (((frameBufWidth) / 64) << 9) | ((psm) << 15)) + +#define GS_RGBA(r, g, b, a) \ + ((r) | ((g) << 8) | ((b) << 16) | ((a) << 24)) + +//DmaPipe defines: + +enum GsRegs { + GPR_PRIM = 0x00, // Select and configure current drawing primitive + GPR_RGBAQ, // Setup current vertex color + GPR_ST, // ... + GPR_UV, // Specify Vertex Texture Coordinates + GPR_XYZF2, // Set vertex coordinate + GPR_XYZ2, // Set vertex coordinate and 'kick' drawing + GPR_TEX0_1, // Texture Buffer Setup (Context 1) + GPR_TEX0_2, // Texture Buffer Setup (Context 2) + GPR_CLAMP_1, // ... + GPR_CLAMP_2, // ... + GPR_FOG, // ... + + GPR_XYZF3 = 0x0C, // ... + GPR_XYZ3, // ... + + GPR_TEX1_1 = 0x14, // ... + GPR_TEX1_2, // ... + GPR_TEX2_1, // ... + GPR_TEX2_2, // ... + GPR_XYOFFSET_1, // Mapping from Primitive to Window coordinate system (Context 1) + GPR_XYOFFSET_2, // Mapping from Primitive to Window coordinate system (Context 2) + GPR_PRMODECONT, // ... + GPR_PRMODE, // ... + GPR_TEXCLUT, // ... + + GPR_SCANMSK = 0x22, // ... + + GPR_MIPTBP1_1 = 0x34, // ... + GPR_MIPTBP1_2, // ... + GPR_MIPTBP2_1, // ... + GPR_MIPTBP2_2, // ... + + GPR_TEXA = 0x3b, // ... + + GPR_FOGCOL = 0x3d, // ... + + GPR_TEXFLUSH = 0x3f,// Write to this register before using newly loaded texture + GPR_SCISSOR_1, // Setup clipping rectangle (Context 1) + GPR_SCISSOR_2, // Setup clipping rectangle (Context 2) + GPR_ALPHA_1, // Setup Alpha Blending Parameters (Context 1) + GPR_ALPHA_2, // Setup Alpha Blending Parameters (Context 2) + GPR_DIMX, // ... + GPR_DTHE, // ... + GPR_COLCLAMP, // ... + GPR_TEST_1, // ... + GPR_TEST_2, // ... + GPR_PABE, // ... + GPR_FBA_1, // ... + GPR_FBA_2, // ... + GPR_FRAME_1, // Frame buffer settings (Context 1) + GPR_FRAME_2, // Frame buffer settings (Context 2) + GPR_ZBUF_1, // ... + GPR_ZBUF_2, // ... + GPR_BITBLTBUF, // Setup Image Transfer Between EE and GS + GPR_TRXPOS, // Setup Image Transfer Coordinates + GPR_TRXREG, // Setup Image Transfer Size + GPR_TRXDIR, // Set Image Transfer Directon + Start Transfer + GPR_HWREG, + + GPR_SIGNAL = 0x60, + GPR_FINISH, + GPR_LABEL +}; + +enum PrimTypes { + PR_POINT = 0, + PR_LINE, + PR_LINESTRIP, + PR_TRIANGLE, + PR_TRIANGLESTRIP, + PR_TRIANGLEFAN, + PR_SPRITE +}; + +#define GS_PSMCT32 0x00 +#define GS_PSMCT24 0x01 +#define GS_PSMCT16 0x02 +#define GS_PSMCT16S 0x0A +#define GS_PSMT8 0x13 +#define GS_PSMT4 0x14 +#define GS_PSMT4HL 0x24 +#define GS_PSMT4HH 0x2C +#define GS_PSMT8H 0x1B + +/*#define GS_SET_BITBLTBUF(sbp, sbw, spsm, dbp, dbw, dpsm) \ + ((uint64)(sbp) | ((uint64)(sbw) << 16) | \ + ((uint64)(spsm) << 24) | ((uint64)(dbp) << 32) | \ + ((uint64)(dbw) << 48) | ((uint64)(dpsm) << 56))*/ + +#define GS_SET_SRC_BLTBUF(sbp, sbw, spsm) \ + ((sbp) | ((uint64)sbw << 16) | ((uint64)spsm << 24)) + +#define GS_SET_DEST_BLTBUF(dbp, dbw, dpsm) \ + (((uint64)(dbp) << 32) | ((uint64)(dbw) << 48) | ((uint64)(dpsm) << 56)) + +#define GS_SET_SRC_TRXPOS(ssax, ssay) \ + ((ssax) | ((uint64)ssay << 16)) + +#define GS_SET_DEST_TRXPOS(dsax, dsay) \ + (((uint64)(dsax) << 32) | ((uint64)(dsay) << 48)) + +#define GS_SET_TRXREG(rrw, rrh) \ + ((uint64)(rrw) | ((uint64)(rrh) << 32)) + +#define GS_SET_TEXA(ta0, aem, ta1) \ + ((uint64)(ta0) | ((uint64)(aem) << 15) | ((uint64)(ta1) << 32)) + +#define GS_SET_TEX0(tbp, tbw, psm, tw, th, tcc, tfx, cbp, cpsm, csm, csa, cld) \ + ((uint64)(tbp) | ((uint64)(tbw) << 14) | ((uint64)(psm) << 20) | ((uint64)(tw) << 26) | \ + ((uint64)(th) << 30) | ((uint64)(tcc) << 34) | ((uint64)(tfx) << 35) | ((uint64)(cbp) << 37) | \ + ((uint64)(cpsm) << 51) | ((uint64)(csm) << 55) | ((uint64)(csa) << 56) | ((uint64)(cld) << 61)) + +#define GIF_SET_TAG(nloop, eop, pre, prim, flg, nreg) \ + ( (uint64)(nloop) | ((uint64)(eop)<<15) | ((uint64)(pre) << 46) | \ + ((uint64)(prim)<<47) | ((uint64)(flg)<<58) | ((uint64)(nreg)<<60) ) + +#define GS_SET_UV(u, v) ((uint64)(u) | ((uint64)(v) << 16)) + +#define GS_SET_XYZ(x, y, z) \ + ((uint64)(x) | ((uint64)(y) << 16) | ((uint64)(z) << 32)) + +#define GS_SET_XYOFFSET(ofx, ofy) ((uint64)(ofx) | ((uint64)(ofy) << 32)) + +#define GS_SET_SCISSOR(scax0, scax1, scay0, scay1) \ + ( (uint64)(scax0) | ((uint64)(scax1) << 16) | ((uint64)(scay0) << 32) | ((uint64)(scay1) << 48) ) + +#define GS_SET_FRAME(fbp, fbw, psm, fbmask) \ + ( (uint64)(fbp) | (uint64)((uint64)(fbw) << 16) | (uint64)((uint64)(psm) << 24) | (uint64)((uint64)(fbmask) << 32) ) + +#define GS_SET_TEST(ate, atst, aref, afail, date, datm, zte, ztst) \ + ( (uint64)(ate) | ((uint64)(atst) << 1) | ((uint64)(aref) << 4) | ((uint64)(afail) << 12) | \ + ((uint64)(date) << 14) | ((uint64)(datm) << 15) | ((uint64)(zte) << 16) | ((uint64)(ztst) << 17) ) + +#define FILTER_NEAREST 0 +#define FILTER_LINEAR 1 + +#define GS_SET_TEX1(lcm, mxl, mmag, mmin, mtba, l, k) \ + ((uint64)(lcm) | ((uint64)(mxl) << 2) | ((uint64)(mmag) << 5) | ((uint64)(mmin) << 6) | \ + ((uint64)(mtba) << 9) | ((uint64)(l) << 19) | ((uint64)(k) << 32)) + +enum AlphaBlendColor { + SOURCE_COLOR = 0, + DEST_COLOR, + ZERO_COLOR +}; + +enum AlphaBlendAlpha { + SOURCE_ALPHA = 0, + DEST_ALPHA, + FIXED_ALPHA +}; + +#define GS_SET_ALPHA(a, b, c, d, fix) \ + ((uint64)(a) | ((uint64)(b)<<2) | ((uint64)(c)<<4) | ((uint64)(d)<<6) | ((uint64)(fix)<<32)) + +#define GS_SET_PRIM(prim, iip, tme, fge, abe, aa1, fst, ctxt, fix) \ + ((uint64)(prim) | ((uint64)(iip) << 3) | ((uint64)(tme) << 4) | \ + ((uint64)(fge) << 5) | ((uint64)(abe) << 6) | ((uint64)(aa1) << 7) | \ + ((uint64)(fst) << 8) | ((uint64)(ctxt) << 9) | ((uint64)(fix) << 10)) + +#define GS_SET_COLQ(c) (0x3f80000000000000 | c) + +#endif // __GSDEFS_H__ diff --git a/backends/platform/ps2/READ_PS2.TXT b/backends/platform/ps2/READ_PS2.TXT new file mode 100644 index 0000000000..59ba25ce38 --- /dev/null +++ b/backends/platform/ps2/READ_PS2.TXT @@ -0,0 +1,82 @@ +ScummVM-PS2 0.8.2 Readme +======================== + +You need a PlayStation 2 with a modchip of your choice in order to run ScummVM. + +ScummVM expects the game data on CD-R/DVD-R, on the Harddisk or on a USB mass + storage device. + + It tries to mount the HDD partition hdd0:+ScummVM on startup and basically + treats it in the same way as the DVD drive. + Creating the partition and putting the datafiles there is up to you. + + Not all USB mass storage devices are supported, but the most common ones should + work. If you attach a device and it gets recognized, it will show up together + with the CD/DVD drive and HDD in the "Add Game" dialog. + + Most USB Mice and Keyboards should work, too. I have a Logitech MX500 mouse that + doesn't work, all the other devices I tried worked fine. + + +Creating a CD-R using CD-Tool +============================= + +Copy any games you want on the CD over into the directory where you extracted + the ZIP file. Don't copy any files directly into the directory of the + ScummVM.ELF, those files are ignored. Instead, have each game in its own + directory. + + File- and directorynames should be DOS 8+3, if they aren't, they'll get + renamed. + + If you run windows, just double click the make_iso.bat. + Wait while it creates the ISO image and burn it with Nero + or any other CD writing software. + + For Linux or Mac OS X binaries check http://www.nobis-crew.org/cd-tool/ + + Unfortunately, writing DVD images with cd-tool is currently broken. + This problem will probably be fixed in the nearer future. + + +If you want to create a CD/DVD without CD-Tool, make sure to put the ELF, + the SYSTEM.CNF and all the IRXs into the CD/DVD's root directory. + + +Notes +===== +- The Curse of Monkey Island only works correctly from HDD. + Playing it from CD/DVD will initially seem to work, but you will + experience random crashes. +- Compressed SAN files need a lot of CPU power, probably because of zlib, + and are constantly out of sync. Uncompressed SANs play fine though, so + compress_san is NOT recommended. +- The cd/dvd drive is a bottleneck, that's why you should compress the games + with MP3 using compress_scumm_sou / compress_scumm_bun / compress_sword1 / + compress_sword2 etc, but NOT compress_san. +- I haven't had time to implement a virtual keyboard. If you don't have a USB + keyboard, you can only enter '1's using the Select button. + (for copy protection screens as well as savegame names) +- When you see '1's and '0's flying across your screen, it means ScummVM is + accessing the Memory Card. Don't switch off or reset the console in that + case, and don't remove the Memory Card either :P + + +GamePad +======= +Start Button - F5 +Select Button - Figure 1 +L1 - 'n' +R1 - 'y' +L2 - Numpad 0 +Triangle - Escape +Square - Enter +Cross - Left mouse button +Circle - Right mouse button +Left analog stick - Mouse. Disabled when USB mouse is detected. + + + +Changes since 0.8.0 RC3 +======================= +- USB Mass support was added diff --git a/backends/platform/ps2/asyncfio.cpp b/backends/platform/ps2/asyncfio.cpp new file mode 100644 index 0000000000..45cadbafa9 --- /dev/null +++ b/backends/platform/ps2/asyncfio.cpp @@ -0,0 +1,206 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "asyncfio.h" +#include <tamtypes.h> +#include <kernel.h> +#include <fileio.h> +#include <assert.h> +#include <string.h> +#include <fileXio_rpc.h> + +#define DEFAULT_MODE (FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IROTH | FIO_S_IWOTH) + +extern void sioprintf(const char *zFormat, ...); + +AsyncFio::AsyncFio(void) { + _runningOp = NULL; + memset((int *)_ioSlots, 0, MAX_HANDLES * sizeof(int)); + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _ioSema = CreateSema(&newSema); +} + +AsyncFio::~AsyncFio(void) { + DeleteSema(_ioSema); +} + +int AsyncFio::open(const char *name, int ioMode) { + WaitSema(_ioSema); + checkSync(); + int res; + fileXioOpen(name, ioMode, DEFAULT_MODE); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +void AsyncFio::close(int handle) { + WaitSema(_ioSema); + checkSync(); + fileXioClose(handle); + int res; + fileXioWaitAsync(FXIO_WAIT, &res); + if (res != 0) + sioprintf("ERROR: fileXioClose failed, EC %d", res); + _ioSlots[handle] = 0; + SignalSema(_ioSema); +} + +void AsyncFio::checkSync(void) { + if (_runningOp) { + fileXioWaitAsync(FXIO_WAIT, (int *)_runningOp); + _runningOp = NULL; + } +} + +void AsyncFio::read(int fd, void *dest, unsigned int len) { + WaitSema(_ioSema); + checkSync(); + assert(fd < MAX_HANDLES); + _runningOp = _ioSlots + fd; + fileXioRead(fd, (unsigned char*)dest, len); + SignalSema(_ioSema); +} + +void AsyncFio::write(int fd, const void *src, unsigned int len) { + WaitSema(_ioSema); + checkSync(); + assert(fd < MAX_HANDLES); + _runningOp = _ioSlots + fd; + fileXioWrite(fd, (unsigned char*)src, len); + SignalSema(_ioSema); +} + +int AsyncFio::seek(int fd, int offset, int whence) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioLseek(fd, offset, whence); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::mkdir(const char *name) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioMkdir(name, DEFAULT_MODE); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::dopen(const char *name) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioDopen(name); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::dread(int fd, iox_dirent_t *dest) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioDread(fd, dest); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +void AsyncFio::dclose(int fd) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioDclose(fd); + fileXioWaitAsync(FXIO_WAIT, &res); + assert(res == 0); + SignalSema(_ioSema); +} + +int AsyncFio::mount(const char *mountpoint, const char *mountstring, int flag) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioMount(mountpoint, mountstring, flag); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::umount(const char *mountpoint) { + int res; + WaitSema(_ioSema); + checkSync(); + fileXioUmount(mountpoint); + fileXioWaitAsync(FXIO_WAIT, &res); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::sync(int fd) { + WaitSema(_ioSema); + if (_runningOp == _ioSlots + fd) + checkSync(); + int res = _ioSlots[fd]; + _ioSlots[fd] = 0; + SignalSema(_ioSema); + return res; +} + +bool AsyncFio::poll(int fd) { + bool retVal = false; + if (PollSema(_ioSema) >= 0) { + if (_runningOp == _ioSlots + fd) { + if (fileXioWaitAsync(FXIO_NOWAIT, (int *)_runningOp) == FXIO_COMPLETE) { + _runningOp = NULL; + retVal = true; + } else + retVal = false; + } else + retVal = true; + SignalSema(_ioSema); + } + return retVal; +} + +bool AsyncFio::fioAvail(void) { + bool retVal = false; + if (PollSema(_ioSema) > 0) { + if (_runningOp) { + if (fileXioWaitAsync(FXIO_NOWAIT, (int *)_runningOp) == FXIO_COMPLETE) { + _runningOp = NULL; + retVal = true; + } else + retVal = false; + } else + retVal = true; + SignalSema(_ioSema); + } + return retVal; +} + diff --git a/backends/platform/ps2/asyncfio.h b/backends/platform/ps2/asyncfio.h new file mode 100644 index 0000000000..ce5145dea2 --- /dev/null +++ b/backends/platform/ps2/asyncfio.h @@ -0,0 +1,50 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#define MAX_HANDLES 32 +#include <sys/stat.h> + +class AsyncFio { +public: + AsyncFio(void); + ~AsyncFio(void); + int open(const char *name, int ioMode); + void close(int handle); + void read(int fd, void *dest, unsigned int len); + void write(int fd, const void *src, unsigned int len); + int seek(int fd, int offset, int whence); + int mkdir(const char *name); + int dopen(const char *name); + int dread(int fd, iox_dirent_t *dest); + void dclose(int fd); + int mount(const char *mountpoint, const char *mountstring, int flag); + int umount(const char *mountpoint); + int sync(int fd); + bool poll(int fd); + bool fioAvail(void); +private: + void checkSync(void); + int _ioSema; + volatile int * volatile _runningOp; + volatile int _ioSlots[MAX_HANDLES]; +}; + diff --git a/backends/platform/ps2/cd.c b/backends/platform/ps2/cd.c new file mode 100644 index 0000000000..5694d9a960 --- /dev/null +++ b/backends/platform/ps2/cd.c @@ -0,0 +1,53 @@ +/********************************************************************* + * Copyright (C) 2003 Tord Lindstrom (pukko@home.se) + * This file is subject to the terms and conditions of the PS2Link License. + * See the file LICENSE in the main directory of this distribution for more + * details. + */ + +#include <tamtypes.h> +#include <kernel.h> +#include <sifrpc.h> + +#define CDVD_INIT_BIND_RPC 0x80000592 + +static SifRpcClientData_t cdvdCd __attribute__((aligned(64))); +static char sendBuffer[256] __attribute__((aligned(16))); + +int cdvdInitialised = 0; + + +void cdvdExit(void) +{ + cdvdInitialised = 0; +} + + +int cdvdInit(int mode) +{ + int i=0,len=0,ret=0; + u8 *pkt; + + cdvdCd.server = NULL; + + do { + if ((ret = SifBindRpc(&cdvdCd, CDVD_INIT_BIND_RPC, 0)) < 0) { + return -1; + } + if (!cdvdCd.server) { + nopdelay(); + } + } + while(!cdvdCd.server); + + pkt = sendBuffer; + PUSHDATA( int, pkt, mode, i); + pkt += i; len += i; + + if ((ret = SifCallRpc(&cdvdCd, 0, 0, sendBuffer, len, NULL, 0, 0, 0)) < 0) + return -1; + + cdvdInitialised = 1; + + return 0; +} diff --git a/backends/platform/ps2/cd.h b/backends/platform/ps2/cd.h new file mode 100644 index 0000000000..2bd1ddfe27 --- /dev/null +++ b/backends/platform/ps2/cd.h @@ -0,0 +1,26 @@ +/********************************************************************* + * Copyright (C) 2003 Tord Lindstrom (pukko@home.se) + * This file is subject to the terms and conditions of the PS2Link License. + * See the file LICENSE in the main directory of this distribution for more + * details. + */ + +#ifndef _CD_H_ +#define _CD_H_ + +#define CDVD_INIT_WAIT 0 +#define CDVD_INIT_NOWAIT 1 +#define CDVD_EXIT 5 + +#ifdef __cplusplus +extern "C" { +#endif + +int cdvdInit(int mode); +void cdvdExit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/backends/platform/ps2/eecodyvdfs.c b/backends/platform/ps2/eecodyvdfs.c new file mode 100644 index 0000000000..655b5b941c --- /dev/null +++ b/backends/platform/ps2/eecodyvdfs.c @@ -0,0 +1,67 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <tamtypes.h> +#include <kernel.h> +#include <sifrpc.h> +#include "eecodyvdfs.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static SifRpcClientData_t cd0; +static unsigned sbuff[64] __attribute__((aligned (64))); + +int driveStopped; + +int initCdvdFs(void) { + int res; + while(((res = SifBindRpc(&cd0, CDVDFS_IRX_ID, 0)) >= 0) && (cd0.server == NULL)) + nopdelay(); + driveStopped = 0; + return res; +} + +void readRTC(struct CdClock *dest) { + SifCallRpc(&cd0, READ_RTC, 0, (void *)sbuff, 0, (void *)sbuff, 8, 0, 0); + memcpy(dest, sbuff, 8); +} + +int driveStop(void) { + if (driveStopped) + return 0; + SifCallRpc(&cd0, DRIVE_STOP, 0, (void *)sbuff, 0, (void *)sbuff, 4, 0, 0); + if (*(int *)sbuff == 0) + driveStopped = 1; + return *(int *)sbuff; +} + +int driveStandby(void) { + if (!driveStopped) + return 0; + SifCallRpc(&cd0, DRIVE_STANDBY, 0, (void *)sbuff, 0, (void *)sbuff, 4, 0, 0); + if (*(int *)sbuff == 0) + driveStopped = 0; + return *(int *)sbuff; +} + + diff --git a/backends/platform/ps2/eecodyvdfs.h b/backends/platform/ps2/eecodyvdfs.h new file mode 100644 index 0000000000..9e58d35687 --- /dev/null +++ b/backends/platform/ps2/eecodyvdfs.h @@ -0,0 +1,52 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef EECDVDFS_H +#define EECDVDFS_H + +#include <tamtypes.h> +#include "iop/CoDyVDfs/common/codyvdirx.h" + +struct CdClock { + u8 stat; + u8 second; + u8 minute; + u8 hour; + u8 padding; + u8 day; + u8 month; + u8 year; +} __attribute__((packed)); + +#ifdef __cplusplus +extern "C" { +#endif + int initCdvdFs(void); + void readRTC(struct CdClock *dest); + int driveStop(void); + int driveStandby(void); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/backends/platform/ps2/fileio.cpp b/backends/platform/ps2/fileio.cpp new file mode 100644 index 0000000000..3b21e0796f --- /dev/null +++ b/backends/platform/ps2/fileio.cpp @@ -0,0 +1,728 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/ps2/fileio.h" + +#include <tamtypes.h> +#include <kernel.h> +#include <fileio.h> +#include <assert.h> +#include <string.h> +#include "backends/ps2/asyncfio.h" +#include "base/engine.h" +#include "common/file.h" +#include "eecodyvdfs.h" +#include "common/config-manager.h" + +#define CACHE_SIZE (2048 * 32) +#define MAX_READ_STEP (2048 * 16) +#define MAX_CACHED_FILES 6 +#define CACHE_READ_THRESHOLD (16 * 2048) +#define CACHE_FILL_MIN (2048 * 24) +#define READ_ALIGN 64 // align all reads to the size of an EE cache line +#define READ_ALIGN_MASK (READ_ALIGN - 1) + +extern void sioprintf(const char *zFormat, ...); + +AsyncFio fio; + +Ps2File::Ps2File(int64 cacheId) { + _cacheId = cacheId; +} + +Ps2File::~Ps2File(void) { +} + +class Ps2ReadFile : public Ps2File { +public: + Ps2ReadFile(int64 cacheId, bool stream); + virtual ~Ps2ReadFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); +private: + void cacheReadAhead(void); + void cacheReadSync(void); + int _fd, _sema; + uint8 *_cacheBuf; + bool _cacheOpRunning; + uint32 _filePos, _physFilePos, _cachePos; + uint32 _fileSize, _bytesInCache, _cacheOfs; + + uint32 _readBytesBlock; + bool _stream; +}; + +Ps2ReadFile::Ps2ReadFile(int64 cacheId, bool stream) : Ps2File(cacheId) { + _fd = -1; + _cacheBuf = (uint8*)memalign(64, CACHE_SIZE); + + _cacheOpRunning = 0; + _filePos = _physFilePos = _cachePos = 0; + _fileSize = _bytesInCache = _cacheOfs = 0; + _cacheOpRunning = false; + _readBytesBlock = 0; + _stream = stream; + + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _sema = CreateSema(&newSema); + assert(_sema >= 0); +} + +Ps2ReadFile::~Ps2ReadFile(void) { + if (_cacheOpRunning) + cacheReadSync(); + free(_cacheBuf); + if (_fd >= 0) + fio.close(_fd); + DeleteSema(_sema); +} + +bool Ps2ReadFile::open(const char *name) { + assert(_fd < 0); + _fd = fio.open(name, O_RDONLY); + if (_fd >= 0) { + _fileSize = fio.seek(_fd, 0, SEEK_END); + fio.seek(_fd, 0, SEEK_SET); + return true; + } else + return false; +} + +uint32 Ps2ReadFile::tell(void) { + WaitSema(_sema); + uint32 res = _filePos; + SignalSema(_sema); + return res; +} + +uint32 Ps2ReadFile::size(void) { + WaitSema(_sema); + uint32 res = _fileSize; + SignalSema(_sema); + return res; +} + +bool Ps2ReadFile::eof(void) { + WaitSema(_sema); + bool res = (_filePos == _fileSize); + SignalSema(_sema); + return res; +} + +int Ps2ReadFile::seek(int32 offset, int origin) { + WaitSema(_sema); + int seekDest; + int res = -1; + switch (origin) { + case SEEK_SET: + seekDest = offset; + break; + case SEEK_CUR: + seekDest = _filePos + offset; + break; + case SEEK_END: + seekDest = _fileSize + offset; + break; + default: + seekDest = -1; + break; + } + if ((seekDest >= 0) && (seekDest <= (int)_fileSize)) { + _filePos = seekDest; + res = 0; + } + SignalSema(_sema); + return res; +} + +void Ps2ReadFile::cacheReadAhead(void) { + if (_cacheOpRunning) { + // there's already some cache read running + if (fio.poll(_fd)) // did it finish? + cacheReadSync(); // yes. + } + if ((!_cacheOpRunning) && ((_readBytesBlock >= CACHE_READ_THRESHOLD) || _stream) && fio.fioAvail()) { + // the engine seems to do sequential reads and there are no other I/Os going on. read ahead. + uint32 cachePosEnd = _cachePos + _bytesInCache; + + if (_cachePos > _filePos) + return; // there was a seek in the meantime, don't cache. + if (cachePosEnd - _filePos >= CACHE_FILL_MIN) + return; // cache is full enough. + if (cachePosEnd == _fileSize) + return; // can't read beyond EOF. + + assert(cachePosEnd < _fileSize); + + if (_cachePos + _bytesInCache <= _filePos) { + _cacheOfs = _bytesInCache = 0; + _cachePos = cachePosEnd = _filePos & ~READ_ALIGN_MASK; + assert(_filePos == _physFilePos); + } else { + uint32 cacheDiff = _filePos - _cachePos; + assert(_bytesInCache >= cacheDiff); + cacheDiff &= ~READ_ALIGN_MASK; + _bytesInCache -= cacheDiff; + _cachePos += cacheDiff; + _cacheOfs = (_cacheOfs + cacheDiff) % CACHE_SIZE; + } + + if (_physFilePos != cachePosEnd) { + sioprintf("unexpected _physFilePos %d cache %d %d", _physFilePos, _cacheOfs, _bytesInCache); + assert(!(cachePosEnd & READ_ALIGN_MASK)); + _physFilePos = fio.seek(_fd, cachePosEnd, SEEK_SET); + if (_physFilePos != cachePosEnd) { + sioprintf("cache seek error: seek to %d instead of %d, fs = %d", _physFilePos, cachePosEnd, _fileSize); + return; + } + } + + uint32 cacheDest = (_cacheOfs + _bytesInCache) % CACHE_SIZE; + uint32 cacheRead = CACHE_SIZE - _bytesInCache; + if (cacheDest + cacheRead > CACHE_SIZE) + cacheRead = CACHE_SIZE - cacheDest; + if (cacheRead > MAX_READ_STEP) + cacheRead = MAX_READ_STEP; + + assert((!(cacheRead & READ_ALIGN_MASK)) && cacheRead); + + _cacheOpRunning = true; + fio.read(_fd, _cacheBuf + cacheDest, cacheRead); + } +} + +void Ps2ReadFile::cacheReadSync(void) { + if (_cacheOpRunning) { + int res = fio.sync(_fd); + assert(res >= 0); + _bytesInCache += res; + _physFilePos += res; + _cacheOpRunning = false; + } +} + +uint32 Ps2ReadFile::read(void *dest, uint32 len) { + WaitSema(_sema); + uint8 *destBuf = (uint8*)dest; + if ((_filePos < _cachePos) || (_filePos + len > _cachePos + _bytesInCache)) + cacheReadSync(); // we have to read from CD, sync cache. + + while (len && (_filePos != _fileSize)) { + if ((_filePos >= _cachePos) && (_filePos < _cachePos + _bytesInCache)) { // read from cache + uint32 staPos = (_cacheOfs + (_filePos - _cachePos)) % CACHE_SIZE; + uint32 cpyLen = _bytesInCache - (_filePos - _cachePos); + if (cpyLen > len) + cpyLen = len; + if (staPos + cpyLen > CACHE_SIZE) + cpyLen = CACHE_SIZE - staPos; + + assert(cpyLen); + memcpy(destBuf, _cacheBuf + staPos, cpyLen); + _filePos += cpyLen; + destBuf += cpyLen; + _readBytesBlock += len; + len -= cpyLen; + } else { // cache miss + assert(!_cacheOpRunning); + if (_physFilePos != _filePos) { + if ((_filePos < _physFilePos) || (_filePos > _physFilePos + (CACHE_SIZE / 2))) + _readBytesBlock = 0; // reset cache hit count + + _physFilePos = _filePos & ~READ_ALIGN_MASK; + if (fio.seek(_fd, _physFilePos, SEEK_SET) != (int)_physFilePos) + break; // read beyond EOF + } + + int doRead = len + (_filePos - _physFilePos); + doRead = (doRead + READ_ALIGN_MASK) & ~READ_ALIGN_MASK; + + if (doRead > MAX_READ_STEP) + doRead = MAX_READ_STEP; + if (doRead < 2048) + doRead = 2048; + + fio.read(_fd, _cacheBuf, doRead); + _cachePos = _physFilePos; + _cacheOfs = 0; + _bytesInCache = fio.sync(_fd); + _physFilePos += _bytesInCache; + if (!_bytesInCache) + break; // EOF + } + } + cacheReadAhead(); + SignalSema(_sema); + return destBuf - (uint8*)dest; +} + +uint32 Ps2ReadFile::write(const void *src, uint32 len) { + sioprintf("write request on Ps2ReadFile!"); + SleepThread(); + return 0; +} + +class Ps2WriteFile : public Ps2File { +public: + Ps2WriteFile(int64 cacheId); + virtual ~Ps2WriteFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); +private: + int _fd; + uint8 *_cacheBuf; + uint32 _filePos, _bytesInCache; +}; + +Ps2WriteFile::Ps2WriteFile(int64 cacheId) : Ps2File(cacheId) { + _fd = -1; + _cacheBuf = (uint8*)malloc(CACHE_SIZE); + _filePos = _bytesInCache = 0; +} + +Ps2WriteFile::~Ps2WriteFile(void) { + if ((_fd >= 0) && (_bytesInCache)) { + fio.write(_fd, _cacheBuf, _bytesInCache); + int wrRes = fio.sync(_fd); + if (wrRes != (int)_bytesInCache) // too late to return an error + printf("Cache flush on fclose(): Unable to write %d cached bytes to mc, only %d bytes written\n", _bytesInCache, wrRes); + } + if (_fd >= 0) + fio.close(_fd); + free(_cacheBuf); +} + +bool Ps2WriteFile::open(const char *name) { + _fd = fio.open(name, O_WRONLY | O_CREAT | O_TRUNC); + return (_fd >= 0); +} + +uint32 Ps2WriteFile::read(void *dest, uint32 len) { + printf("ERROR: Read request on Ps2WriteFile\n"); + SleepThread(); + return 0; +} + +uint32 Ps2WriteFile::write(const void *src, uint32 len) { + uint32 size = len; + uint8 *srcBuf = (uint8*)src; + while (size) { + uint32 doCpy = (len > CACHE_SIZE - _bytesInCache) ? (CACHE_SIZE - _bytesInCache) : len; + if (doCpy) { + memcpy(_cacheBuf + _bytesInCache, srcBuf, doCpy); + _bytesInCache += doCpy; + srcBuf += doCpy; + size -= doCpy; + } + + if (_bytesInCache == CACHE_SIZE) { + fio.write(_fd, _cacheBuf, _bytesInCache); + if (fio.sync(_fd) != (int)_bytesInCache) { + printf("Unable to flush %d cached bytes to memory card!\n", _bytesInCache); + return 0; + } + _filePos += _bytesInCache; + _bytesInCache = 0; + } + } + return len; +} + +uint32 Ps2WriteFile::tell(void) { + return _bytesInCache + _filePos; +} + +uint32 Ps2WriteFile::size(void) { + return tell(); +} + +int Ps2WriteFile::seek(int32 offset, int origin) { + printf("Seek(%d/%d) request on Ps2WriteFile\n", offset, origin); + SleepThread(); + return 0; +} + +bool Ps2WriteFile::eof(void) { + return true; +} + +struct TocNode { + char name[64]; + TocNode *next, *sub; + bool isDir; + uint8 nameLen; +}; + +class TocManager { +public: + TocManager(void); + ~TocManager(void); + void readEntries(const char *root); + int64 fileExists(const char *name); + bool haveEntries(void); +private: + void readDir(const char *path, TocNode **node, int level); + TocNode *_rootNode; + char _root[256]; + uint8 _rootLen; +}; + +static TocManager tocManager; + +struct FioHandleCache { + Ps2File *file; + FioHandleCache *next, *prev; +}; + +static FioHandleCache *cacheListStart = NULL; +static FioHandleCache *cacheListEnd = NULL; +static int cacheListLen = 0; +static int openFileCount = 0; +static int cacheListSema = -1; + +static bool checkedPath = false; + +Ps2File *findInCache(int64 id); + +FILE *ps2_fopen(const char *fname, const char *mode) { + if (cacheListSema == -1) { + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + cacheListSema = CreateSema(&newSema); + assert(cacheListSema >= 0); + } + + printf("ps2_fopen: %s, %s\n", fname, mode); + + if (!checkedPath && g_engine) { + // are we playing from cd/dvd? + const char *gameDataPath = ConfMan.get("path").c_str(); + printf("Read TOC dir: %s\n", gameDataPath); + if (strncmp(gameDataPath, "cdfs:", 5) != 0) + driveStop(); // no, we aren't. stop the drive. it's noisy. + // now cache the dir tree + tocManager.readEntries(gameDataPath); + checkedPath = true; + } + + if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) { + printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); + return NULL; + } + + bool rdOnly = (mode[0] == 'r'); + + int64 cacheId = -1; + if (rdOnly && tocManager.haveEntries()) + cacheId = tocManager.fileExists(fname); + + if (cacheId != 0) { + Ps2File *file = findInCache(cacheId); + if (file) + return (FILE*)file; + + if (rdOnly) { + bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun"); + file = new Ps2ReadFile(cacheId, isAudioFile); + } else + file = new Ps2WriteFile(cacheId); + + if (file->open(fname)) { + openFileCount++; + return (FILE*)file; + } else + delete file; + } + return NULL; +} + +void checkCacheListLen(void) { + while ((cacheListLen > MAX_CACHED_FILES) || ((openFileCount > 13) && cacheListLen)) { + assert(cacheListEnd && cacheListStart); + delete cacheListEnd->file; + if (cacheListEnd->prev) { + cacheListEnd->prev->next = NULL; + FioHandleCache *temp = cacheListEnd; + cacheListEnd = cacheListEnd->prev; + delete temp; + } else { + assert(cacheListEnd == cacheListStart); + assert(cacheListLen == 1); + delete cacheListEnd; + cacheListEnd = cacheListStart = NULL; + } + cacheListLen--; + openFileCount--; + } +} + +int ps2_fclose(FILE *stream) { + Ps2File *file = (Ps2File*)stream; + if (file->_cacheId > 0) { // this is a file on the CD, could be smart to cache it + FioHandleCache *newHandle = new FioHandleCache; + newHandle->file = file; + file->seek(0, SEEK_SET); + + WaitSema(cacheListSema); + if (!cacheListEnd) { + assert(!cacheListStart); + newHandle->prev = newHandle->next = NULL; + cacheListEnd = cacheListStart = newHandle; + } else { + assert(cacheListStart); + newHandle->prev = NULL; + newHandle->next = cacheListStart; + cacheListStart->prev = newHandle; + cacheListStart = newHandle; + } + cacheListLen++; + checkCacheListLen(); + SignalSema(cacheListSema); + } else { + openFileCount--; + delete file; + } + return 0; +} + +Ps2File *findInCache(int64 id) { + if (id <= 0) + return NULL; + WaitSema(cacheListSema); + FioHandleCache *node = cacheListStart; + while (node) { + if (node->file->_cacheId == id) { + if (node == cacheListStart) + cacheListStart = node->next; + if (node == cacheListEnd) + cacheListEnd = node->prev; + if (node->prev) + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + Ps2File *ret = node->file; + delete node; + cacheListLen--; + SignalSema(cacheListSema); + return ret; + } else + node = node->next; + } + SignalSema(cacheListSema); + return NULL; +} + +int ps2_fseek(FILE *stream, long offset, int origin) { + return ((Ps2File*)stream)->seek(offset, origin); +} + +uint32 ps2_ftell(FILE *stream) { + return ((Ps2File*)stream)->tell(); +} + +uint32 ps2_fsize(FILE *stream) { + return ((Ps2File*)stream)->size(); +} + +int ps2_feof(FILE *stream) { + return ((Ps2File*)stream)->eof(); +} + +size_t ps2_fread(void *buf, size_t r, size_t n, FILE *stream) { + assert(r != 0); + return ((Ps2File*)stream)->read(buf, r * n) / r; +} + +int ps2_fgetc(FILE *stream) { + uint8 temp; + if (((Ps2File*)stream)->read(&temp, 1)) + return temp; + else + return EOF; +} + +char *ps2_fgets(char *buf, int n, FILE *stream) { + char *retVal = buf; + while (n--) { + if (n == 0) + *buf = '\0'; + else { + char c = ps2_fgetc(stream); + if (c == EOF) + return NULL; + if ((c == '\r') || (c == '\n')) { + *buf++ = '\0'; + return retVal; + } + *buf++ = c; + } + } + return retVal; +} + +int ps2_fprintf(FILE *pOut, const char *zFormat, ...) { + va_list ap; + char resStr[2048]; + + va_start(ap,zFormat); + int res = vsnprintf(resStr, 2048, zFormat, ap); + va_end(ap); + if ((pOut == stderr) || (pOut == stdout)) { + printf("%s", resStr); + sioprintf("%s", resStr); + } else + res = ps2_fwrite(resStr, 1, res, pOut); + return res; +} + +size_t ps2_fwrite(const void *buf, size_t r, size_t n, FILE *stream) { + assert(r != 0); + return ((Ps2File*)stream)->write(buf, r * n) / r; +} + +int ps2_fputc(int c, FILE *stream) { + if (((Ps2File*)stream)->write(&c, 1) == 1) + return c; + else + return -1; +} + +int ps2_fputs(const char *s, FILE *stream) { + int len = strlen(s); + if (ps2_fwrite(s, 1, len, stream) == (size_t)len) + return len; + else + return EOF; +} + +int ps2_fflush(FILE *stream) { + printf("fflush not implemented\n"); + return 0; +} + +TocManager::TocManager(void) { + _rootNode = NULL; +} + +TocManager::~TocManager(void) { +} + +bool TocManager::haveEntries(void) { + return _rootNode != NULL; +} + +void TocManager::readEntries(const char *root) { + _rootLen = strlen(root); + strcpy(_root, root); + while (_root[_rootLen - 1] == '/') { + _rootLen--; + _root[_rootLen] = '\0'; + } + char readPath[256]; + sprintf(readPath, "%s/", _root); + printf("readDir: %s\n", readPath); + readDir(readPath, &_rootNode, 0); +} + +void TocManager::readDir(const char *path, TocNode **node, int level) { + if (level <= 2) { // we don't scan deeper than that + iox_dirent_t dirent; + int fd = fio.dopen(path); + if (fd >= 0) { + while (fio.dread(fd, &dirent) > 0) + if (dirent.name[0] != '.') { // skip '.' and '..' + *node = new TocNode; + (*node)->sub = (*node)->next = NULL; + + (*node)->nameLen = strlen(dirent.name); + memcpy((*node)->name, dirent.name, (*node)->nameLen + 1); + + if (dirent.stat.mode & FIO_S_IFDIR) { // directory + (*node)->isDir = true; + char nextPath[256]; + sprintf(nextPath, "%s%s/", path, dirent.name); + readDir(nextPath, &((*node)->sub), level + 1); + } else + (*node)->isDir = false; + node = &((*node)->next); + } + fio.dclose(fd); + } else + printf("Can't open path: %s\n", path); + } +} + +int64 TocManager::fileExists(const char *name) { + if (((name[_rootLen] != '/') && (name[_rootLen] != '\0')) || (strnicmp(name, _root, _rootLen) != 0)) { + for (int i = 0; i < 8; i++) + if (name[i] == ':') // we don't know the content of other drives, + return -1; // assume file exists + else if ((name[i] == '/') || (name[i] == '\\')) + return 0; // does not exists (this is probably ScummVM trying the 'current directory'.) + return 0; + } + + uint8 nameLen = strlen(name); + + name += _rootLen + 1; + nameLen -= _rootLen + 1; + + TocNode *node = _rootNode; + int64 retId = 1; + while (node) { + if (((name[node->nameLen] == '/') || (name[node->nameLen] == '\0')) && (strnicmp(name, node->name, node->nameLen) == 0)) { + name += node->nameLen; + nameLen -= node->nameLen; + if (node->isDir) { + if (nameLen) { + name++; // skip '/' + nameLen--; + node = node->sub; + retId <<= 10; + } else + return 0; // can't open a directory with fopen() + } else { + if (nameLen == 0) + return retId; // ok, found + else + return 0; // here's a file, but there's something left in the path + } + } else { + node = node->next; + retId++; + } + } + return 0; // does not exist +} + diff --git a/backends/platform/ps2/fileio.h b/backends/platform/ps2/fileio.h new file mode 100644 index 0000000000..ed94c2db6a --- /dev/null +++ b/backends/platform/ps2/fileio.h @@ -0,0 +1,77 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __PS2FILE_IO__ +#define __PS2FILE_IO__ + +#include "common/scummsys.h" + +class Ps2File { +public: + Ps2File(int64 cacheId); + virtual ~Ps2File(void); + virtual bool open(const char *name) = 0; + virtual uint32 read(void *dest, uint32 len) = 0; + virtual uint32 write(const void *src, uint32 len) = 0; + virtual uint32 tell(void) = 0; + virtual uint32 size(void) = 0; + virtual int seek(int32 offset, int origin) = 0; + virtual bool eof(void) = 0; + int64 _cacheId; +private: +}; + +class Ps2SmushFile : public Ps2File { +public: + Ps2SmushFile(int64 cacheId); + virtual ~Ps2SmushFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); +private: + uint32 _filePos, _fileSize; + int _id; +}; + +FILE *ps2_fopen(const char *fname, const char *mode); +int ps2_fclose(FILE *stream); +int ps2_fflush(FILE *stream); +int ps2_fseek(FILE *stream, long offset, int origin); +uint32 ps2_ftell(FILE *stream); +int ps2_feof(FILE *stream); +uint32 ps2_fsize(FILE *stream); + +size_t ps2_fread(void *buf, size_t r, size_t n, FILE *stream); +int ps2_fgetc(FILE *stream); +char *ps2_fgets(char *buf, int n, FILE *stream); + +size_t ps2_fwrite(const void *buf, size_t r, size_t n, FILE *stream); +int ps2_fputc(int c, FILE *stream); +int ps2_fputs(const char *s, FILE *stream); +int ps2_fprintf(FILE *pOut, const char *zFormat, ...); + +#endif // __PS2FILE_IO__ + diff --git a/backends/platform/ps2/icon.cpp b/backends/platform/ps2/icon.cpp new file mode 100644 index 0000000000..db46ac5987 --- /dev/null +++ b/backends/platform/ps2/icon.cpp @@ -0,0 +1,932 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/ps2/savefile.h" +#include "backends/ps2/Gs2dScreen.h" +#include "backends/ps2/GsDefs.h" + +const iconIVECTOR Ps2SaveFileManager::_bgcolor[4] = { + { 68, 23, 116, 0 }, // top left + { 255, 255, 255, 0 }, // top right + { 255, 255, 255, 0 }, // bottom left + { 68, 23, 116, 0 }, // bottom right +}; + +const iconFVECTOR Ps2SaveFileManager::_lightdir[3] = { + { 0.5, 0.5, 0.5, 0.0 }, + { 0.0,-0.4,-0.1, 0.0 }, + {-0.5,-0.5, 0.5, 0.0 }, +}; + +const iconFVECTOR Ps2SaveFileManager::_lightcol[3] = { + { 0.3, 0.3, 0.3, 0.00 }, + { 0.4, 0.4, 0.4, 0.00 }, + { 0.5, 0.5, 0.5, 0.00 }, +}; + +const iconFVECTOR Ps2SaveFileManager::_ambient = { 0.50, 0.50, 0.50, 0.00 }; + +// Source File: stdico2.rle +// Orig. Offset: 0 / 0x00000000 +// Length: 14018 / 0x000036C2 (bytes) + +const uint8 Ps2SaveFileManager::_rleIcoData[14018] = { + 0xCC, 0x41, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x24, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0xFE, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0x02, + 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xC1, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0x02, + 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0xDC, 0x00, 0xF7, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xC1, 0x00, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x7F, 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0xFE, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, + 0x7F, 0x80, 0x00, 0x24, 0x00, 0xF7, 0x00, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x7F, 0x7F, 0x7F, 0x80, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x4E, 0x07, + 0x0C, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE7, 0x03, 0xE6, 0x03, 0xE9, 0x03, 0xF0, 0x2B, 0xF8, 0x57, 0x74, 0x00, 0x0C, 0x00, 0xFD, 0x73, + 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE6, 0x03, + 0xE9, 0x03, 0xF0, 0x2B, 0xF8, 0x57, 0x62, 0x00, 0x21, 0x00, 0xFE, 0x77, 0xFB, 0x67, 0xF9, 0x5F, + 0xF8, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, + 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF9, 0x5F, 0xF7, 0x53, + 0xF1, 0x33, 0xEB, 0x13, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE9, 0x03, 0xED, 0x1F, 0xF3, 0x3F, 0xF9, 0x5B, 0xFB, 0x67, 0xFE, 0x77, 0x5F, 0x00, 0x21, 0x00, + 0xFB, 0x6B, 0xF5, 0x4B, 0xF0, 0x2F, 0xEE, 0x2F, 0xF0, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, + 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, 0xF1, 0x2F, + 0xF1, 0x2F, 0xF0, 0x2F, 0xEF, 0x2B, 0xEC, 0x1B, 0xE9, 0x0B, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xEA, 0x0F, 0xEC, 0x1F, 0xF1, 0x2F, 0xF6, 0x4B, + 0xFC, 0x6B, 0x5F, 0x00, 0x21, 0x00, 0xF8, 0x57, 0xEF, 0x2B, 0xE8, 0x07, 0xE6, 0x07, 0xE8, 0x07, + 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, 0xEA, 0x07, + 0xEA, 0x07, 0xEA, 0x07, 0xE9, 0x07, 0xE9, 0x07, 0xE9, 0x07, 0xE8, 0x07, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, + 0xE7, 0x07, 0xE9, 0x07, 0xF0, 0x2B, 0xF8, 0x57, 0x56, 0x00, 0x30, 0x00, 0xFD, 0x73, 0xFB, 0x67, + 0xFA, 0x63, 0xF9, 0x63, 0xFA, 0x63, 0xFA, 0x63, 0xFA, 0x63, 0xFA, 0x63, 0xF9, 0x5F, 0xF2, 0x3B, + 0xEB, 0x13, 0xE5, 0x03, 0xE3, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE5, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xEC, 0x13, 0xF3, 0x3B, + 0xF9, 0x5F, 0xFA, 0x63, 0xF9, 0x63, 0xFA, 0x63, 0xFB, 0x6B, 0xFE, 0x77, 0x50, 0x00, 0x30, 0x00, + 0xFA, 0x63, 0xF5, 0x43, 0xF1, 0x37, 0xF0, 0x37, 0xF2, 0x37, 0xF2, 0x37, 0xF2, 0x37, 0xF2, 0x37, + 0xF1, 0x33, 0xEE, 0x1F, 0xE9, 0x07, 0xE6, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE7, 0x03, 0xE7, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE7, 0x03, 0xE6, 0x03, 0xE7, 0x03, + 0xEA, 0x07, 0xEE, 0x1F, 0xF1, 0x33, 0xF1, 0x37, 0xF0, 0x37, 0xF1, 0x37, 0xF5, 0x47, 0xFB, 0x67, + 0x4F, 0x00, 0x32, 0x00, 0xFD, 0x77, 0xF6, 0x4B, 0xEE, 0x1F, 0xE9, 0x0B, 0xE8, 0x0B, 0xEA, 0x0B, + 0xEA, 0x0B, 0xEA, 0x0B, 0xEA, 0x0B, 0xEA, 0x0B, 0xEA, 0x07, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xEA, 0x07, 0xEA, 0x0B, 0xEA, 0x0B, 0xE8, 0x0B, + 0xE9, 0x0B, 0xEF, 0x23, 0xF7, 0x4F, 0xFE, 0x7B, 0x49, 0x00, 0x39, 0x00, 0xFD, 0x73, 0xFB, 0x6B, + 0xFA, 0x67, 0xFB, 0x67, 0xFB, 0x67, 0xF8, 0x57, 0xF0, 0x2F, 0xE9, 0x07, 0xE4, 0x03, 0xE4, 0x03, + 0xE5, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xA8, 0x03, + 0xA8, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE6, 0x03, 0xE5, 0x03, + 0xE4, 0x03, 0xE5, 0x03, 0xEA, 0x0B, 0xF1, 0x33, 0xF8, 0x5B, 0xFC, 0x6B, 0xFE, 0x77, 0x46, 0x00, + 0x3A, 0x00, 0xFF, 0x7B, 0xF9, 0x5F, 0xF4, 0x43, 0xF1, 0x3B, 0xF2, 0x3B, 0xF3, 0x3B, 0xF1, 0x2F, + 0xEC, 0x17, 0xE8, 0x03, 0xE5, 0x03, 0xE5, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xC8, 0x03, + 0xC8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x47, 0x03, 0x47, 0x03, 0x27, 0x03, 0x27, 0x03, 0x47, 0x03, + 0x68, 0x03, 0x88, 0x03, 0xA8, 0x03, 0xC8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xEC, 0x1B, + 0xF0, 0x33, 0xF5, 0x47, 0xFB, 0x63, 0x46, 0x00, 0x3B, 0x00, 0xFC, 0x6F, 0xF4, 0x43, 0xED, 0x1B, + 0xE9, 0x0F, 0xE9, 0x0F, 0xEB, 0x0F, 0xEB, 0x0F, 0xE9, 0x07, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0xA7, 0x03, + 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0x88, 0x03, 0x67, 0x03, 0x27, 0x03, 0x06, 0x03, 0xC5, 0x02, + 0xA6, 0x02, 0xA6, 0x02, 0xA6, 0x02, 0xC6, 0x02, 0xE7, 0x02, 0x27, 0x07, 0x67, 0x03, 0x87, 0x03, + 0xC7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x07, 0xE9, 0x0F, 0xEF, 0x23, 0xF6, 0x4F, 0xFE, 0x77, + 0x43, 0x00, 0x40, 0x00, 0xFD, 0x77, 0xFC, 0x6F, 0xF6, 0x4F, 0xEF, 0x27, 0xE8, 0x03, 0xE4, 0x03, + 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xC7, 0x03, + 0xC7, 0x03, 0xA7, 0x03, 0x67, 0x03, 0x47, 0x03, 0x27, 0x03, 0x06, 0x03, 0x06, 0x03, 0xE6, 0x02, + 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xC6, 0x02, 0x85, 0x02, 0x65, 0x02, 0x24, 0x02, 0x04, 0x02, + 0x04, 0x02, 0x05, 0x02, 0x25, 0x02, 0x45, 0x06, 0x85, 0x06, 0xC6, 0x02, 0x06, 0x03, 0x46, 0x03, + 0x87, 0x03, 0xA7, 0x03, 0xC8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xE7, 0x03, 0xE5, 0x03, 0xE5, 0x03, 0xEA, 0x07, 0xF1, 0x33, 0xF8, 0x5B, 0xFC, 0x6F, + 0xFD, 0x77, 0xFF, 0x7B, 0x3F, 0x00, 0x41, 0x00, 0xFE, 0x77, 0xF9, 0x5B, 0xF5, 0x43, 0xEF, 0x2F, + 0xEB, 0x13, 0xE7, 0x03, 0xE5, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x26, 0x03, 0xE6, 0x02, 0xA6, 0x02, 0x65, 0x02, + 0x45, 0x02, 0x45, 0x02, 0x45, 0x02, 0x24, 0x02, 0x24, 0x02, 0x24, 0x02, 0x04, 0x02, 0xE4, 0x01, + 0xC4, 0x01, 0xA3, 0x05, 0x83, 0x05, 0x63, 0x01, 0x83, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xE4, 0x01, + 0x24, 0x02, 0x65, 0x02, 0xC6, 0x02, 0x26, 0x03, 0x67, 0x03, 0xA7, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, + 0xEC, 0x1B, 0xF1, 0x37, 0xF5, 0x47, 0xF9, 0x5F, 0xFD, 0x73, 0x3F, 0x00, 0x41, 0x00, 0xFC, 0x6B, + 0xF4, 0x43, 0xED, 0x1B, 0xE9, 0x0F, 0xE8, 0x07, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0x86, 0x03, 0x26, 0x03, 0xA5, 0x02, + 0x24, 0x02, 0xE4, 0x01, 0xC4, 0x01, 0x84, 0x01, 0x84, 0x01, 0x84, 0x01, 0x83, 0x01, 0x63, 0x01, + 0x63, 0x01, 0x63, 0x01, 0x43, 0x01, 0x43, 0x05, 0x23, 0x05, 0x23, 0x05, 0x02, 0x05, 0x02, 0x05, + 0x02, 0x05, 0x22, 0x01, 0x43, 0x01, 0x83, 0x01, 0xC4, 0x01, 0x25, 0x02, 0xA6, 0x02, 0x06, 0x03, + 0x67, 0x03, 0xA7, 0x03, 0xC8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x0B, 0xEA, 0x13, 0xEE, 0x23, 0xF5, 0x47, 0xFC, 0x6B, + 0x39, 0x00, 0x47, 0x00, 0xFF, 0x7B, 0xFE, 0x77, 0xFD, 0x73, 0xFC, 0x73, 0xFD, 0x73, 0xFD, 0x73, + 0xF7, 0x4F, 0xEF, 0x23, 0xE8, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x66, 0x03, 0xE5, 0x02, 0x85, 0x02, + 0x04, 0x02, 0x83, 0x01, 0x43, 0x01, 0x23, 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, 0x01, + 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x04, 0xE3, 0x04, 0xE3, 0x08, 0xE2, 0x08, 0xC2, 0x08, + 0xC2, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xE2, 0x00, 0x03, 0x01, 0x23, 0x01, 0xA4, 0x01, 0x05, 0x02, + 0x65, 0x02, 0xE6, 0x02, 0x46, 0x03, 0x87, 0x03, 0xC8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE5, 0x03, 0xE5, 0x03, 0xEA, 0x07, 0xF2, 0x37, + 0xFB, 0x67, 0x39, 0x00, 0x47, 0x00, 0xFD, 0x73, 0xF8, 0x5B, 0xF5, 0x47, 0xF4, 0x47, 0xF4, 0x47, + 0xF5, 0x47, 0xF1, 0x2F, 0xEC, 0x13, 0xE7, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, + 0xA7, 0x03, 0x87, 0x03, 0x87, 0x03, 0x47, 0x03, 0x46, 0x03, 0x26, 0x03, 0xC5, 0x02, 0x64, 0x02, + 0xE4, 0x01, 0x83, 0x01, 0x23, 0x05, 0x03, 0x05, 0xE3, 0x04, 0xC3, 0x04, 0xE3, 0x04, 0xE3, 0x00, + 0xE2, 0x00, 0xC2, 0x04, 0xC2, 0x04, 0xC2, 0x04, 0xE2, 0x04, 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x08, + 0xE2, 0x08, 0xC2, 0x04, 0xC2, 0x04, 0xA2, 0x04, 0xC2, 0x04, 0xC2, 0x04, 0x03, 0x01, 0x43, 0x01, + 0xA4, 0x01, 0xE4, 0x01, 0x65, 0x02, 0xE6, 0x02, 0x47, 0x03, 0xA8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE5, 0x03, 0xE4, 0x03, 0xE9, 0x03, + 0xF2, 0x33, 0xFA, 0x67, 0x39, 0x00, 0x47, 0x00, 0xFA, 0x63, 0xF3, 0x3B, 0xED, 0x1B, 0xEB, 0x1B, + 0xEC, 0x1B, 0xED, 0x1B, 0xEB, 0x13, 0xEA, 0x07, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0xA7, 0x03, + 0x87, 0x03, 0x46, 0x03, 0x26, 0x03, 0x06, 0x03, 0xE5, 0x02, 0xA5, 0x02, 0x85, 0x02, 0x44, 0x02, + 0xC4, 0x01, 0x63, 0x01, 0x03, 0x05, 0xE3, 0x04, 0xE3, 0x04, 0xE3, 0x04, 0xE3, 0x04, 0xE3, 0x04, + 0x03, 0x05, 0xE2, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE2, 0x08, 0x03, 0x09, 0x23, 0x09, 0x23, 0x09, + 0x23, 0x09, 0x03, 0x05, 0x03, 0x05, 0xE3, 0x08, 0xC3, 0x08, 0xC3, 0x08, 0xE3, 0x04, 0xE3, 0x04, + 0x23, 0x01, 0x43, 0x01, 0x83, 0x05, 0xE4, 0x05, 0x66, 0x02, 0x07, 0x03, 0x88, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xEB, 0x0F, 0xF3, 0x3B, 0xFB, 0x67, 0x36, 0x00, 0x4A, 0x00, 0xFF, 0x7B, 0xFE, 0x77, 0xFC, 0x6F, + 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0xA7, 0x03, 0x66, 0x03, 0x26, 0x03, 0x06, 0x03, 0xC5, 0x02, 0x85, 0x02, 0x65, 0x06, + 0x44, 0x06, 0x04, 0x02, 0xE3, 0x01, 0x83, 0x01, 0x43, 0x01, 0x03, 0x05, 0xC3, 0x04, 0xC3, 0x08, + 0xC3, 0x08, 0xE3, 0x08, 0x04, 0x09, 0x03, 0x09, 0x03, 0x05, 0x03, 0x09, 0x03, 0x09, 0x03, 0x09, + 0x23, 0x09, 0x23, 0x09, 0x44, 0x09, 0x44, 0x09, 0x44, 0x09, 0x24, 0x09, 0x23, 0x09, 0x03, 0x09, + 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x04, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0x63, 0x05, + 0xE5, 0x05, 0x86, 0x02, 0x27, 0x03, 0xA8, 0x03, 0xC7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xEB, 0x0F, 0xF3, 0x3B, 0xFB, 0x67, 0x36, 0x00, + 0x4A, 0x00, 0xFD, 0x6F, 0xF9, 0x5B, 0xF5, 0x47, 0xEF, 0x2B, 0xEA, 0x0B, 0xE6, 0x03, 0xE4, 0x03, + 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA7, 0x03, 0x47, 0x03, 0xE6, 0x02, 0xA5, 0x02, + 0x65, 0x02, 0x24, 0x02, 0x04, 0x06, 0xE4, 0x05, 0xA3, 0x05, 0x83, 0x01, 0x43, 0x01, 0x22, 0x01, + 0xE2, 0x04, 0xC2, 0x04, 0xA2, 0x08, 0xC3, 0x08, 0xE3, 0x08, 0x03, 0x09, 0x24, 0x09, 0x24, 0x09, + 0x44, 0x09, 0x44, 0x09, 0x44, 0x09, 0x24, 0x09, 0x44, 0x09, 0x64, 0x09, 0x65, 0x09, 0x65, 0x09, + 0x64, 0x09, 0x44, 0x09, 0x23, 0x09, 0x03, 0x09, 0xE3, 0x08, 0xC3, 0x08, 0xE3, 0x08, 0x03, 0x09, + 0x23, 0x09, 0x03, 0x09, 0xE3, 0x04, 0x23, 0x05, 0x83, 0x01, 0x25, 0x02, 0xC6, 0x02, 0x47, 0x03, + 0xA7, 0x03, 0xC7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xEB, 0x0F, 0xF3, 0x3B, 0xFB, 0x67, 0x36, 0x00, 0x4A, 0x00, 0xFA, 0x5F, 0xF3, 0x3B, 0xED, 0x1F, + 0xE9, 0x13, 0xE8, 0x07, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA7, 0x03, + 0x47, 0x03, 0xE6, 0x02, 0x65, 0x02, 0x24, 0x02, 0xE4, 0x05, 0xA3, 0x05, 0x63, 0x05, 0x63, 0x05, + 0x43, 0x01, 0x23, 0x01, 0x02, 0x01, 0xE2, 0x00, 0xC2, 0x04, 0xC2, 0x04, 0xC2, 0x08, 0xE3, 0x08, + 0x03, 0x09, 0x24, 0x09, 0x44, 0x09, 0x65, 0x09, 0x65, 0x09, 0x65, 0x09, 0x65, 0x09, 0x64, 0x09, + 0x64, 0x09, 0x85, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x65, 0x0D, 0x44, 0x0D, 0x23, 0x0D, 0xE3, 0x0C, + 0xC3, 0x08, 0xC3, 0x08, 0x03, 0x09, 0x24, 0x0D, 0x45, 0x0D, 0x24, 0x09, 0x03, 0x05, 0x02, 0x05, + 0x63, 0x01, 0xE3, 0x01, 0x65, 0x02, 0x06, 0x03, 0x67, 0x03, 0xC8, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xEB, 0x0F, 0xF3, 0x3B, 0xFB, 0x67, 0x34, 0x00, + 0x4C, 0x00, 0xFF, 0x7B, 0xFC, 0x6F, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA7, 0x03, 0x46, 0x03, 0xC6, 0x02, 0x45, 0x02, + 0xE5, 0x01, 0x84, 0x05, 0x63, 0x05, 0x23, 0x05, 0x03, 0x05, 0x03, 0x05, 0x03, 0x05, 0xE3, 0x00, + 0xC2, 0x00, 0xC2, 0x04, 0xC2, 0x04, 0xE2, 0x08, 0xE3, 0x08, 0x03, 0x09, 0x24, 0x09, 0x44, 0x09, + 0x65, 0x09, 0x86, 0x09, 0x86, 0x0D, 0xA6, 0x0D, 0x86, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0xA6, 0x0D, + 0xA6, 0x0D, 0xA6, 0x0D, 0x86, 0x0D, 0x65, 0x0D, 0x24, 0x0D, 0x03, 0x0D, 0xE3, 0x0C, 0xE3, 0x08, + 0x24, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x44, 0x09, 0x03, 0x05, 0xE2, 0x04, 0x22, 0x01, 0xA3, 0x01, + 0x24, 0x02, 0xC5, 0x02, 0x47, 0x03, 0xA8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE6, 0x03, 0xE6, 0x03, 0xEB, 0x0F, 0xF3, 0x3B, 0xFB, 0x67, 0x32, 0x00, 0x4E, 0x00, 0xFE, 0x7B, + 0xFC, 0x6B, 0xF9, 0x5B, 0xF5, 0x4B, 0xEF, 0x2B, 0xEA, 0x0B, 0xE5, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0x87, 0x03, 0x46, 0x03, 0xC6, 0x02, 0x45, 0x02, 0xC4, 0x01, + 0x64, 0x01, 0x43, 0x05, 0x23, 0x05, 0x03, 0x09, 0x03, 0x09, 0x04, 0x09, 0x04, 0x05, 0x04, 0x05, + 0xE3, 0x04, 0xE3, 0x04, 0x03, 0x09, 0x03, 0x09, 0x23, 0x0D, 0x44, 0x0D, 0x44, 0x0D, 0x65, 0x0D, + 0x85, 0x0D, 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x11, 0xA6, 0x11, 0xC6, 0x11, + 0xC7, 0x0D, 0xA7, 0x0D, 0x86, 0x0D, 0x65, 0x0D, 0x45, 0x0D, 0x24, 0x0D, 0x04, 0x0D, 0x04, 0x0D, + 0x44, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x44, 0x09, 0x03, 0x05, 0xE2, 0x04, 0x22, 0x01, 0x63, 0x01, + 0x04, 0x02, 0xA5, 0x02, 0x26, 0x03, 0xA7, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE5, 0x03, 0xE4, 0x03, 0xE9, 0x07, 0xF2, 0x37, 0xFB, 0x67, 0x32, 0x00, 0x4E, 0x00, 0xFD, 0x77, + 0xF8, 0x57, 0xF2, 0x37, 0xED, 0x23, 0xEA, 0x13, 0xE9, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xC7, 0x03, 0x87, 0x03, 0x27, 0x03, 0xC6, 0x02, 0x45, 0x02, 0xC4, 0x01, 0x63, 0x01, + 0x23, 0x01, 0x03, 0x05, 0x23, 0x05, 0x23, 0x09, 0x24, 0x09, 0x45, 0x09, 0x45, 0x09, 0x45, 0x09, + 0x44, 0x09, 0x44, 0x09, 0x44, 0x09, 0x44, 0x0D, 0x64, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x86, 0x0D, + 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x0D, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, + 0xC6, 0x11, 0xA6, 0x0D, 0xA6, 0x0D, 0x86, 0x0D, 0x66, 0x0D, 0x45, 0x0D, 0x45, 0x0D, 0x45, 0x0D, + 0x65, 0x0D, 0x85, 0x0D, 0x85, 0x09, 0x44, 0x09, 0x03, 0x05, 0xE3, 0x04, 0x23, 0x01, 0x83, 0x01, + 0x04, 0x02, 0xA5, 0x02, 0x26, 0x03, 0x87, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, + 0xE4, 0x03, 0xE3, 0x03, 0xE8, 0x03, 0xF1, 0x33, 0xFA, 0x63, 0x32, 0x00, 0x4E, 0x00, 0xFD, 0x73, + 0xF5, 0x47, 0xED, 0x17, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xC8, 0x03, + 0xA7, 0x03, 0x66, 0x03, 0x06, 0x03, 0xA5, 0x02, 0x25, 0x06, 0xA4, 0x05, 0x43, 0x05, 0x02, 0x01, + 0xE2, 0x04, 0x03, 0x05, 0x23, 0x05, 0x44, 0x09, 0x65, 0x09, 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x0D, + 0x65, 0x09, 0x85, 0x09, 0x84, 0x09, 0x84, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x86, 0x0D, + 0x86, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x85, 0x11, 0x85, 0x11, 0xA6, 0x11, 0xA6, 0x11, + 0xA6, 0x11, 0xA6, 0x11, 0xA6, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x66, 0x0D, 0x66, 0x11, 0x65, 0x0D, + 0x65, 0x0D, 0x85, 0x0D, 0x64, 0x09, 0x44, 0x09, 0x04, 0x05, 0x03, 0x05, 0x44, 0x01, 0x84, 0x01, + 0x05, 0x02, 0xA6, 0x02, 0x26, 0x03, 0x87, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE6, 0x03, 0xE6, 0x03, 0xEB, 0x13, 0xF3, 0x3B, 0xFB, 0x67, 0x32, 0x00, 0x4E, 0x00, 0xFC, 0x6F, + 0xF4, 0x3F, 0xEB, 0x0F, 0xE5, 0x03, 0xE4, 0x03, 0xE7, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x87, 0x03, + 0x46, 0x03, 0xE6, 0x02, 0x65, 0x02, 0x04, 0x02, 0xA4, 0x05, 0x23, 0x05, 0xE2, 0x04, 0xC2, 0x04, + 0xC2, 0x04, 0xE3, 0x08, 0x24, 0x09, 0x64, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x85, 0x0D, + 0x85, 0x0D, 0x85, 0x09, 0x85, 0x09, 0x85, 0x09, 0x85, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x65, 0x0D, + 0x65, 0x0D, 0x45, 0x0D, 0x44, 0x09, 0x24, 0x0D, 0x24, 0x0D, 0x24, 0x0D, 0x44, 0x11, 0x65, 0x11, + 0x85, 0x11, 0x86, 0x11, 0xA6, 0x11, 0x87, 0x11, 0x87, 0x0D, 0x87, 0x0D, 0x86, 0x11, 0x86, 0x0D, + 0x85, 0x0D, 0x85, 0x0D, 0x64, 0x09, 0x24, 0x09, 0x04, 0x05, 0x04, 0x01, 0x44, 0x01, 0xC4, 0x01, + 0x45, 0x02, 0xC6, 0x02, 0x46, 0x03, 0xA7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE9, 0x07, + 0xEA, 0x17, 0xED, 0x23, 0xF1, 0x33, 0xF7, 0x53, 0xFC, 0x6F, 0x32, 0x00, 0x4E, 0x00, 0xFD, 0x6F, + 0xF4, 0x43, 0xEC, 0x13, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA7, 0x03, 0x26, 0x03, + 0xC6, 0x02, 0x45, 0x02, 0xC4, 0x01, 0x63, 0x01, 0x23, 0x05, 0xE2, 0x04, 0xC2, 0x04, 0xC2, 0x04, + 0xC2, 0x08, 0x03, 0x09, 0x44, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x85, 0x11, 0x85, 0x0D, 0x85, 0x0D, + 0x85, 0x09, 0x85, 0x09, 0x85, 0x09, 0x65, 0x09, 0x65, 0x09, 0x64, 0x09, 0x44, 0x09, 0x44, 0x09, + 0x24, 0x09, 0x04, 0x09, 0xE3, 0x08, 0xC3, 0x08, 0xC3, 0x08, 0xC2, 0x08, 0xE3, 0x0C, 0x03, 0x0D, + 0x44, 0x0D, 0x65, 0x11, 0x86, 0x11, 0xA7, 0x11, 0xA7, 0x11, 0xA7, 0x0D, 0xA6, 0x0D, 0x85, 0x0D, + 0x85, 0x0D, 0x65, 0x0D, 0x45, 0x09, 0x24, 0x09, 0x04, 0x05, 0x23, 0x01, 0x64, 0x01, 0xE5, 0x01, + 0x86, 0x02, 0x06, 0x03, 0x67, 0x03, 0xA8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xEB, 0x0F, + 0xEF, 0x2B, 0xF4, 0x4B, 0xF8, 0x5B, 0xFB, 0x6B, 0xFE, 0x77, 0x32, 0x00, 0x4B, 0x00, 0xFD, 0x73, + 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x87, 0x03, 0x46, 0x03, 0xA5, 0x02, + 0x24, 0x02, 0xA4, 0x01, 0x23, 0x01, 0xE2, 0x00, 0xC2, 0x04, 0xC2, 0x08, 0xA2, 0x08, 0xC2, 0x08, + 0xE3, 0x08, 0x24, 0x0D, 0x64, 0x0D, 0x85, 0x11, 0x85, 0x11, 0x85, 0x0D, 0x85, 0x0D, 0x85, 0x0D, + 0x85, 0x09, 0x65, 0x09, 0x65, 0x05, 0x65, 0x05, 0x64, 0x05, 0x44, 0x05, 0x43, 0x05, 0x23, 0x05, + 0xE3, 0x04, 0xC3, 0x04, 0xA3, 0x04, 0x62, 0x04, 0x61, 0x04, 0x41, 0x04, 0x81, 0x08, 0xA2, 0x08, + 0x03, 0x0D, 0x44, 0x0D, 0x66, 0x11, 0x87, 0x11, 0xA7, 0x11, 0xC7, 0x0D, 0xA6, 0x0D, 0xA5, 0x0D, + 0x85, 0x0D, 0x65, 0x0D, 0x44, 0x09, 0x24, 0x09, 0x03, 0x05, 0x23, 0x01, 0xA4, 0x01, 0x25, 0x02, + 0xC6, 0x02, 0x47, 0x03, 0x87, 0x03, 0xA8, 0x03, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xEC, 0x13, + 0xF4, 0x3F, 0xFB, 0x6B, 0x35, 0x00, 0x4B, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, + 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xC8, 0x03, 0x87, 0x03, 0x26, 0x03, 0xA5, 0x02, 0x04, 0x02, 0x83, 0x01, 0x02, 0x01, 0xA2, 0x00, + 0x82, 0x04, 0xA2, 0x04, 0xA2, 0x08, 0xC2, 0x08, 0xE3, 0x08, 0x24, 0x0D, 0x44, 0x0D, 0x64, 0x0D, + 0x65, 0x0D, 0x64, 0x0D, 0x64, 0x0D, 0x44, 0x0D, 0x64, 0x09, 0x64, 0x09, 0x64, 0x05, 0x84, 0x05, + 0x84, 0x05, 0x84, 0x05, 0x64, 0x01, 0x43, 0x01, 0x22, 0x01, 0xE2, 0x00, 0xA2, 0x04, 0x82, 0x04, + 0x41, 0x04, 0x21, 0x04, 0x21, 0x04, 0x41, 0x04, 0x81, 0x08, 0xC2, 0x08, 0x24, 0x0D, 0x65, 0x0D, + 0x86, 0x0D, 0xC7, 0x11, 0xC6, 0x0D, 0xC6, 0x0D, 0xA5, 0x0D, 0x84, 0x0D, 0x44, 0x09, 0x24, 0x09, + 0x23, 0x05, 0x23, 0x05, 0x64, 0x01, 0xE4, 0x01, 0x66, 0x02, 0x06, 0x03, 0x67, 0x03, 0x88, 0x03, + 0xA8, 0x03, 0xC7, 0x03, 0xC5, 0x03, 0xC5, 0x03, 0xEB, 0x13, 0xF5, 0x47, 0xFE, 0x77, 0x35, 0x00, + 0x4B, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xEC, 0x1B, 0xE6, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA8, 0x03, 0x47, 0x03, 0xC6, 0x02, + 0x24, 0x02, 0x83, 0x01, 0x02, 0x01, 0xA1, 0x00, 0x61, 0x00, 0x82, 0x04, 0xA2, 0x08, 0xC3, 0x08, + 0xE3, 0x08, 0x24, 0x0D, 0x44, 0x0D, 0x64, 0x0D, 0x64, 0x0D, 0x64, 0x0D, 0x44, 0x0D, 0x24, 0x0D, + 0x24, 0x09, 0x24, 0x09, 0x44, 0x05, 0x63, 0x05, 0x84, 0x01, 0x84, 0x01, 0xA4, 0x01, 0x83, 0x01, + 0x63, 0x01, 0x22, 0x01, 0xE2, 0x00, 0xC1, 0x00, 0xA1, 0x00, 0x61, 0x00, 0x41, 0x04, 0x21, 0x04, + 0x41, 0x04, 0x61, 0x04, 0xA2, 0x04, 0xE3, 0x08, 0x44, 0x0D, 0x86, 0x0D, 0xC6, 0x0D, 0xC6, 0x11, + 0xC5, 0x0D, 0xA5, 0x0D, 0x64, 0x09, 0x44, 0x09, 0x23, 0x05, 0x23, 0x05, 0x43, 0x05, 0xA4, 0x05, + 0x25, 0x02, 0xA6, 0x02, 0x27, 0x03, 0x87, 0x03, 0xA8, 0x03, 0xA7, 0x03, 0xC6, 0x03, 0xC4, 0x03, + 0xC4, 0x03, 0xEA, 0x0B, 0xF4, 0x3F, 0xFD, 0x73, 0x35, 0x00, 0x4B, 0x00, 0xFD, 0x73, 0xF4, 0x47, + 0xEC, 0x1B, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0x68, 0x03, 0xE6, 0x02, 0x25, 0x02, 0x84, 0x05, 0xE2, 0x04, 0xA1, 0x00, + 0x81, 0x00, 0x61, 0x00, 0x82, 0x04, 0xA3, 0x08, 0xE4, 0x08, 0x24, 0x0D, 0x65, 0x0D, 0x85, 0x0D, + 0x85, 0x09, 0x64, 0x09, 0x44, 0x09, 0x44, 0x09, 0x24, 0x09, 0x24, 0x09, 0x43, 0x05, 0x63, 0x05, + 0x83, 0x01, 0xA3, 0x01, 0xE3, 0x01, 0xE4, 0x01, 0xC3, 0x01, 0xA3, 0x01, 0x63, 0x01, 0x42, 0x01, + 0x02, 0x01, 0xE2, 0x00, 0xA1, 0x00, 0x61, 0x00, 0x41, 0x04, 0x41, 0x04, 0x61, 0x04, 0x82, 0x04, + 0xE3, 0x04, 0x24, 0x09, 0x85, 0x0D, 0xC6, 0x0D, 0xC6, 0x11, 0xC5, 0x0D, 0xA5, 0x0D, 0x64, 0x09, + 0x23, 0x09, 0x03, 0x05, 0x23, 0x05, 0x63, 0x05, 0xC4, 0x05, 0x65, 0x02, 0xC6, 0x02, 0x47, 0x03, + 0x87, 0x03, 0xA7, 0x03, 0x87, 0x03, 0xA6, 0x03, 0xC5, 0x03, 0xC5, 0x03, 0xEB, 0x0F, 0xF4, 0x3F, + 0xFC, 0x6B, 0x35, 0x00, 0x4B, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xEC, 0x1B, 0xE6, 0x03, 0xE6, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0x87, 0x03, 0x06, 0x03, + 0x45, 0x02, 0xA4, 0x01, 0x02, 0x05, 0x82, 0x04, 0x81, 0x04, 0x81, 0x00, 0x82, 0x04, 0xA2, 0x04, + 0xC3, 0x08, 0x04, 0x09, 0x44, 0x09, 0x65, 0x0D, 0x85, 0x0D, 0x65, 0x09, 0x44, 0x09, 0x44, 0x09, + 0x44, 0x05, 0x64, 0x05, 0x84, 0x05, 0xA4, 0x05, 0xC3, 0x01, 0x03, 0x02, 0x24, 0x02, 0x44, 0x02, + 0x64, 0x02, 0x44, 0x02, 0x24, 0x02, 0x04, 0x02, 0xC3, 0x01, 0xA3, 0x01, 0x63, 0x01, 0x02, 0x01, + 0xA1, 0x00, 0x61, 0x00, 0x41, 0x04, 0x61, 0x04, 0xA2, 0x04, 0xE3, 0x08, 0x44, 0x09, 0x85, 0x0D, + 0xA6, 0x0D, 0xA6, 0x11, 0xA5, 0x0D, 0x85, 0x0D, 0x44, 0x09, 0x23, 0x05, 0x02, 0x05, 0x23, 0x01, + 0x63, 0x01, 0xE4, 0x01, 0x65, 0x02, 0xE6, 0x02, 0x67, 0x03, 0xA7, 0x03, 0xA6, 0x03, 0x86, 0x03, + 0xA7, 0x07, 0xC9, 0x13, 0xEB, 0x1B, 0xF1, 0x2F, 0xF7, 0x4F, 0xFD, 0x73, 0x35, 0x00, 0x4B, 0x00, + 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0x87, 0x03, 0x26, 0x03, 0xA5, 0x02, 0xE4, 0x01, 0x42, 0x01, 0xC2, 0x00, + 0x61, 0x00, 0x82, 0x04, 0xC2, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC3, 0x08, 0x03, 0x09, 0x44, 0x09, + 0x64, 0x09, 0x85, 0x09, 0x44, 0x09, 0x24, 0x09, 0x23, 0x09, 0x64, 0x05, 0xA4, 0x05, 0x04, 0x02, + 0x44, 0x02, 0x64, 0x02, 0x84, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, + 0xA5, 0x02, 0x65, 0x02, 0x45, 0x02, 0x04, 0x02, 0x83, 0x01, 0xE2, 0x00, 0x81, 0x00, 0x41, 0x00, + 0x81, 0x04, 0xE2, 0x08, 0x24, 0x09, 0x65, 0x0D, 0x86, 0x0D, 0xA6, 0x11, 0xA6, 0x11, 0x85, 0x0D, + 0x65, 0x0D, 0x24, 0x09, 0x03, 0x05, 0x02, 0x05, 0x23, 0x01, 0x63, 0x01, 0xC4, 0x01, 0x45, 0x02, + 0xC6, 0x02, 0x46, 0x03, 0x86, 0x03, 0x85, 0x03, 0x86, 0x03, 0xA9, 0x0F, 0xCE, 0x2B, 0xF3, 0x43, + 0xF7, 0x53, 0xFB, 0x67, 0xFE, 0x77, 0x35, 0x00, 0x4A, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, + 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xC8, 0x03, 0x67, 0x03, + 0xE6, 0x02, 0x24, 0x02, 0x63, 0x01, 0xE1, 0x00, 0x81, 0x00, 0x81, 0x00, 0xC3, 0x04, 0x04, 0x05, + 0x04, 0x09, 0x04, 0x09, 0x03, 0x05, 0x03, 0x09, 0x43, 0x09, 0x64, 0x09, 0x64, 0x09, 0x24, 0x09, + 0x03, 0x09, 0x24, 0x05, 0x84, 0x05, 0x04, 0x02, 0x85, 0x02, 0xC5, 0x02, 0x05, 0x03, 0x26, 0x03, + 0x46, 0x03, 0x47, 0x03, 0x47, 0x03, 0x47, 0x03, 0x47, 0x03, 0x27, 0x03, 0x07, 0x03, 0xE7, 0x02, + 0xA6, 0x02, 0x04, 0x02, 0x43, 0x01, 0xA1, 0x00, 0x61, 0x00, 0xA2, 0x04, 0x03, 0x09, 0x44, 0x0D, + 0x65, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x66, 0x0D, 0x45, 0x0D, 0x24, 0x09, 0x24, 0x09, 0x03, 0x05, + 0x23, 0x05, 0x43, 0x01, 0x63, 0x01, 0xC4, 0x01, 0x45, 0x02, 0xC5, 0x02, 0x46, 0x03, 0x86, 0x03, + 0x84, 0x03, 0x85, 0x03, 0xAB, 0x17, 0xD3, 0x3F, 0xFB, 0x67, 0xFE, 0x77, 0xFE, 0x7B, 0x36, 0x00, + 0x48, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xC8, 0x03, 0x26, 0x03, 0x85, 0x02, 0xC3, 0x01, 0x02, 0x01, 0xA1, 0x00, + 0x61, 0x00, 0x62, 0x04, 0xC3, 0x04, 0x25, 0x09, 0x45, 0x09, 0x44, 0x09, 0x24, 0x09, 0x23, 0x09, + 0x23, 0x09, 0x43, 0x09, 0x43, 0x05, 0x43, 0x05, 0x43, 0x05, 0x84, 0x05, 0x04, 0x02, 0x65, 0x02, + 0x05, 0x03, 0x46, 0x03, 0x66, 0x03, 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0x88, 0x03, 0xA8, 0x03, + 0xA8, 0x03, 0x88, 0x03, 0x87, 0x03, 0x67, 0x03, 0x27, 0x03, 0x65, 0x02, 0xA3, 0x01, 0xE2, 0x00, + 0x81, 0x00, 0xA2, 0x04, 0x03, 0x09, 0x24, 0x09, 0x44, 0x0D, 0x44, 0x0D, 0x24, 0x0D, 0x24, 0x0D, + 0x04, 0x09, 0x04, 0x09, 0xE3, 0x08, 0x03, 0x05, 0x23, 0x05, 0x63, 0x01, 0xA4, 0x01, 0x05, 0x02, + 0x85, 0x02, 0xE6, 0x02, 0x46, 0x03, 0x85, 0x03, 0x83, 0x03, 0x84, 0x03, 0xAC, 0x1B, 0xD5, 0x4B, + 0xFF, 0x7B, 0x38, 0x00, 0x48, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA7, 0x03, 0x06, 0x03, 0x45, 0x02, 0x83, 0x01, + 0xE2, 0x00, 0x81, 0x00, 0x61, 0x04, 0x82, 0x04, 0xE4, 0x08, 0x45, 0x09, 0x66, 0x09, 0x65, 0x09, + 0x45, 0x09, 0x24, 0x09, 0x23, 0x09, 0x03, 0x05, 0x23, 0x05, 0x43, 0x05, 0x83, 0x05, 0xE4, 0x01, + 0x65, 0x02, 0xC6, 0x02, 0x26, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA7, 0x03, + 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x47, 0x03, 0xA5, 0x02, + 0xC4, 0x01, 0x22, 0x01, 0xA2, 0x00, 0xA2, 0x04, 0xC2, 0x04, 0xC2, 0x08, 0xC3, 0x08, 0xC3, 0x08, + 0xC3, 0x08, 0xC3, 0x08, 0xA3, 0x08, 0xC3, 0x08, 0xC2, 0x04, 0xE2, 0x04, 0x22, 0x01, 0x83, 0x01, + 0xE4, 0x01, 0x45, 0x02, 0xC6, 0x02, 0x06, 0x03, 0x47, 0x03, 0x85, 0x03, 0x82, 0x03, 0x63, 0x03, + 0x8A, 0x13, 0xD5, 0x47, 0xFE, 0x7B, 0x38, 0x00, 0x48, 0x00, 0xFD, 0x73, 0xF5, 0x47, 0xED, 0x1B, + 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0x87, 0x03, 0xC5, 0x02, + 0x24, 0x02, 0x63, 0x01, 0xC2, 0x00, 0x82, 0x00, 0x62, 0x04, 0x83, 0x08, 0xE4, 0x08, 0x45, 0x09, + 0x66, 0x09, 0x86, 0x0D, 0x65, 0x0D, 0x44, 0x0D, 0x03, 0x09, 0x03, 0x05, 0x22, 0x01, 0x63, 0x01, + 0xE4, 0x01, 0x65, 0x02, 0xC6, 0x02, 0x06, 0x03, 0x47, 0x03, 0x68, 0x03, 0x68, 0x03, 0x87, 0x03, + 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, + 0x67, 0x03, 0xC5, 0x02, 0x24, 0x02, 0x63, 0x01, 0xC2, 0x00, 0xA2, 0x00, 0xA2, 0x00, 0x81, 0x04, + 0x81, 0x04, 0x81, 0x04, 0x81, 0x04, 0x81, 0x04, 0x82, 0x04, 0xA2, 0x04, 0xC2, 0x04, 0x02, 0x01, + 0x63, 0x01, 0xC3, 0x01, 0x24, 0x02, 0xA6, 0x02, 0x07, 0x03, 0x47, 0x03, 0x67, 0x03, 0x86, 0x03, + 0x63, 0x03, 0x64, 0x03, 0x8B, 0x13, 0xD4, 0x43, 0xFD, 0x73, 0x38, 0x00, 0x48, 0x00, 0xFD, 0x73, + 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, + 0x46, 0x03, 0x85, 0x02, 0xC4, 0x01, 0x03, 0x01, 0xA2, 0x00, 0x82, 0x04, 0x82, 0x04, 0xC3, 0x08, + 0x04, 0x09, 0x65, 0x09, 0x86, 0x0D, 0x86, 0x0D, 0x65, 0x0D, 0x45, 0x0D, 0x03, 0x09, 0xE2, 0x04, + 0x22, 0x01, 0xA3, 0x01, 0x44, 0x02, 0xC5, 0x02, 0x26, 0x03, 0x47, 0x03, 0x88, 0x03, 0x88, 0x03, + 0x68, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0x66, 0x03, 0x66, 0x03, 0x66, 0x03, 0x66, 0x03, + 0x66, 0x03, 0x87, 0x03, 0x66, 0x03, 0x06, 0x03, 0x85, 0x02, 0xE4, 0x01, 0x63, 0x01, 0x23, 0x01, + 0xE2, 0x00, 0xA1, 0x00, 0x61, 0x00, 0x61, 0x00, 0x41, 0x00, 0x41, 0x00, 0x61, 0x04, 0xA2, 0x04, + 0x02, 0x01, 0x42, 0x01, 0xC3, 0x01, 0x44, 0x02, 0x85, 0x02, 0xE6, 0x02, 0x47, 0x03, 0x67, 0x03, + 0x67, 0x03, 0x88, 0x07, 0x88, 0x0B, 0x8A, 0x13, 0xAF, 0x2B, 0xD6, 0x4F, 0xFD, 0x73, 0x38, 0x00, + 0x48, 0x00, 0xFF, 0x7B, 0xF6, 0x4F, 0xEE, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0xA8, 0x03, 0x26, 0x03, 0x65, 0x02, 0xA3, 0x01, 0xE2, 0x00, 0x81, 0x00, 0x82, 0x00, + 0xA2, 0x04, 0xC3, 0x08, 0x24, 0x09, 0x65, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x65, 0x0D, 0x44, 0x0D, + 0x23, 0x09, 0x02, 0x05, 0x62, 0x05, 0xE3, 0x01, 0x85, 0x02, 0x26, 0x03, 0x67, 0x03, 0x87, 0x03, + 0x87, 0x03, 0x88, 0x03, 0x68, 0x03, 0x47, 0x03, 0x47, 0x03, 0x46, 0x03, 0x46, 0x03, 0x46, 0x03, + 0x46, 0x03, 0x46, 0x03, 0x46, 0x03, 0x86, 0x03, 0x87, 0x03, 0x46, 0x03, 0x06, 0x03, 0x85, 0x02, + 0x24, 0x02, 0xC4, 0x01, 0x63, 0x01, 0x02, 0x01, 0xA1, 0x00, 0x61, 0x00, 0x41, 0x00, 0x41, 0x00, + 0x81, 0x00, 0xE2, 0x00, 0x43, 0x01, 0xA3, 0x01, 0x25, 0x02, 0xA5, 0x02, 0xE6, 0x02, 0x27, 0x03, + 0x47, 0x03, 0x66, 0x03, 0x67, 0x03, 0x8A, 0x0F, 0xAD, 0x27, 0xB2, 0x3B, 0xD6, 0x4F, 0xFA, 0x63, + 0xFE, 0x7B, 0x38, 0x00, 0x47, 0x00, 0xFF, 0x7B, 0xF6, 0x4F, 0xEE, 0x1B, 0xE7, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x88, 0x03, 0x06, 0x03, 0x24, 0x02, 0x63, 0x01, 0xC1, 0x00, + 0x61, 0x00, 0x81, 0x00, 0xC2, 0x04, 0xE3, 0x08, 0x24, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x0D, + 0x44, 0x0D, 0x44, 0x09, 0x23, 0x09, 0x22, 0x05, 0x83, 0x05, 0x24, 0x02, 0xC5, 0x02, 0x46, 0x03, + 0x66, 0x03, 0x87, 0x03, 0x67, 0x03, 0x67, 0x03, 0x47, 0x03, 0x27, 0x03, 0x06, 0x03, 0x06, 0x03, + 0x05, 0x03, 0xE5, 0x02, 0xE5, 0x02, 0x06, 0x03, 0x26, 0x03, 0x46, 0x03, 0x66, 0x03, 0x66, 0x03, + 0x46, 0x03, 0x06, 0x03, 0xA5, 0x02, 0x64, 0x02, 0x04, 0x02, 0x83, 0x01, 0xE2, 0x00, 0xA2, 0x00, + 0x62, 0x00, 0x81, 0x00, 0xC2, 0x00, 0x42, 0x01, 0xC4, 0x01, 0x25, 0x02, 0xA6, 0x02, 0x07, 0x03, + 0x27, 0x03, 0x47, 0x03, 0x66, 0x03, 0x65, 0x03, 0x67, 0x03, 0xAC, 0x1B, 0xD3, 0x3F, 0xFA, 0x63, + 0xFC, 0x6F, 0xFE, 0x77, 0x37, 0x00, 0x46, 0x00, 0xFE, 0x7B, 0xFD, 0x73, 0xFA, 0x63, 0xF3, 0x3F, + 0xEC, 0x17, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x88, 0x03, 0x47, 0x03, 0xA6, 0x02, + 0xE4, 0x01, 0x22, 0x01, 0x81, 0x00, 0x61, 0x00, 0x82, 0x00, 0xE3, 0x04, 0x23, 0x09, 0x44, 0x0D, + 0x64, 0x0D, 0x65, 0x11, 0x44, 0x0D, 0x44, 0x0D, 0x23, 0x09, 0x23, 0x09, 0x22, 0x05, 0x83, 0x05, + 0x04, 0x02, 0x85, 0x02, 0x06, 0x03, 0x26, 0x03, 0x26, 0x03, 0x06, 0x03, 0xE6, 0x02, 0xC6, 0x02, + 0xA6, 0x02, 0x85, 0x02, 0x85, 0x02, 0x65, 0x02, 0x64, 0x02, 0x65, 0x02, 0x85, 0x02, 0xA5, 0x02, + 0xC5, 0x02, 0xE5, 0x02, 0x06, 0x03, 0x26, 0x03, 0x26, 0x03, 0x06, 0x03, 0xC5, 0x02, 0x85, 0x02, + 0x04, 0x02, 0x83, 0x01, 0x23, 0x01, 0xE2, 0x00, 0xE2, 0x00, 0x43, 0x01, 0xC3, 0x01, 0x24, 0x02, + 0xA6, 0x02, 0x07, 0x03, 0x47, 0x03, 0x67, 0x03, 0x67, 0x03, 0x66, 0x03, 0x64, 0x03, 0x86, 0x03, + 0xAD, 0x1F, 0xD7, 0x53, 0x39, 0x00, 0x47, 0x00, 0xFE, 0x77, 0xFA, 0x63, 0xF6, 0x4F, 0xF2, 0x3F, + 0xEE, 0x27, 0xEA, 0x0F, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x67, 0x03, 0x06, 0x03, + 0x65, 0x02, 0xA3, 0x01, 0xE2, 0x00, 0x61, 0x00, 0x61, 0x04, 0xA2, 0x04, 0xE3, 0x08, 0x24, 0x09, + 0x64, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x44, 0x0D, 0x24, 0x0D, 0x03, 0x09, 0x02, 0x05, 0x22, 0x05, + 0x62, 0x01, 0xC3, 0x01, 0x24, 0x02, 0x85, 0x02, 0x85, 0x02, 0x84, 0x02, 0x64, 0x02, 0x44, 0x02, + 0x24, 0x02, 0x04, 0x02, 0xE4, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0x04, 0x02, + 0x04, 0x02, 0x24, 0x02, 0x44, 0x02, 0x65, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xE6, 0x02, 0x06, 0x03, + 0xE5, 0x02, 0xA5, 0x02, 0x24, 0x02, 0xA4, 0x01, 0x83, 0x01, 0x83, 0x01, 0xC4, 0x01, 0x24, 0x02, + 0x85, 0x02, 0xE6, 0x02, 0x27, 0x03, 0x67, 0x03, 0x68, 0x03, 0x88, 0x03, 0x86, 0x03, 0x63, 0x03, + 0x84, 0x03, 0xAC, 0x1B, 0xD6, 0x4F, 0x39, 0x00, 0x48, 0x00, 0xFC, 0x6F, 0xF6, 0x4F, 0xEF, 0x2B, + 0xEA, 0x17, 0xE8, 0x0F, 0xE8, 0x07, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x47, 0x03, + 0xC6, 0x02, 0x24, 0x02, 0x63, 0x01, 0xC2, 0x00, 0x61, 0x04, 0x62, 0x04, 0xA3, 0x08, 0x04, 0x09, + 0x44, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x65, 0x0D, 0x44, 0x0D, 0x04, 0x09, 0xE3, 0x08, 0xE3, 0x04, + 0x02, 0x01, 0x22, 0x01, 0x62, 0x01, 0xA3, 0x01, 0xE3, 0x01, 0xE3, 0x01, 0xE3, 0x01, 0xC3, 0x05, + 0xA3, 0x01, 0x83, 0x01, 0x63, 0x01, 0x63, 0x01, 0x63, 0x01, 0x63, 0x01, 0x63, 0x01, 0x84, 0x01, + 0x84, 0x01, 0x84, 0x01, 0x83, 0x01, 0x83, 0x01, 0xC3, 0x01, 0xE4, 0x01, 0x45, 0x06, 0x85, 0x02, + 0xE6, 0x02, 0x06, 0x03, 0xE6, 0x02, 0xA5, 0x02, 0x44, 0x02, 0x24, 0x02, 0x24, 0x02, 0x45, 0x02, + 0x85, 0x02, 0xC6, 0x02, 0x06, 0x03, 0x46, 0x03, 0x67, 0x03, 0x67, 0x03, 0x88, 0x03, 0x85, 0x03, + 0x83, 0x03, 0x83, 0x03, 0xAB, 0x17, 0xD5, 0x4B, 0xFE, 0x77, 0x38, 0x00, 0x48, 0x00, 0xFB, 0x6B, + 0xF3, 0x3F, 0xEA, 0x0F, 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xA8, 0x03, 0x26, 0x03, 0x85, 0x02, 0xC3, 0x01, 0x22, 0x01, 0xA1, 0x00, 0x61, 0x04, 0x62, 0x04, + 0xA3, 0x08, 0x04, 0x09, 0x45, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x45, 0x0D, 0x04, 0x0D, + 0xE4, 0x08, 0xE3, 0x04, 0x03, 0x05, 0x02, 0x01, 0x22, 0x01, 0x43, 0x01, 0x63, 0x01, 0x63, 0x05, + 0x63, 0x05, 0x42, 0x05, 0x42, 0x05, 0x22, 0x05, 0x02, 0x01, 0x02, 0x01, 0x02, 0x05, 0x23, 0x05, + 0x23, 0x05, 0x23, 0x05, 0x44, 0x05, 0x44, 0x05, 0x23, 0x01, 0x23, 0x01, 0x43, 0x01, 0x83, 0x05, + 0xC4, 0x05, 0x25, 0x06, 0x85, 0x02, 0xC5, 0x02, 0x06, 0x03, 0xE5, 0x02, 0xC5, 0x02, 0xA5, 0x02, + 0xC6, 0x02, 0xC6, 0x02, 0xE6, 0x02, 0x06, 0x03, 0x26, 0x03, 0x46, 0x03, 0x66, 0x03, 0x87, 0x03, + 0x87, 0x03, 0x87, 0x03, 0x86, 0x07, 0x88, 0x0B, 0xAE, 0x27, 0xD6, 0x4F, 0xFD, 0x77, 0x38, 0x00, + 0x48, 0x00, 0xFB, 0x6B, 0xF2, 0x3B, 0xE9, 0x0B, 0xE4, 0x03, 0xE4, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xA7, 0x03, 0x06, 0x03, 0x64, 0x02, 0xA3, 0x01, 0x02, 0x01, 0x81, 0x00, + 0x41, 0x04, 0x41, 0x04, 0x82, 0x04, 0xE3, 0x08, 0x24, 0x09, 0x45, 0x0D, 0x65, 0x0D, 0x65, 0x0D, + 0x45, 0x0D, 0x25, 0x0D, 0x24, 0x09, 0x04, 0x09, 0x24, 0x05, 0x23, 0x05, 0x23, 0x05, 0x43, 0x05, + 0x43, 0x05, 0x43, 0x05, 0x43, 0x09, 0x43, 0x09, 0x43, 0x09, 0x43, 0x05, 0x43, 0x05, 0x43, 0x05, + 0x23, 0x05, 0x23, 0x05, 0x23, 0x05, 0x44, 0x05, 0x44, 0x05, 0x44, 0x05, 0x44, 0x05, 0x23, 0x05, + 0x43, 0x05, 0x43, 0x05, 0x84, 0x05, 0xC4, 0x05, 0x04, 0x06, 0x44, 0x02, 0xA5, 0x02, 0xC5, 0x02, + 0xE5, 0x02, 0x06, 0x03, 0x06, 0x03, 0x27, 0x03, 0x27, 0x03, 0x47, 0x03, 0x66, 0x03, 0x66, 0x03, + 0x66, 0x03, 0x66, 0x03, 0x87, 0x03, 0x89, 0x0F, 0xAC, 0x23, 0xD0, 0x33, 0xD4, 0x47, 0xF9, 0x63, + 0xFE, 0x7B, 0x38, 0x00, 0x47, 0x00, 0xFC, 0x6B, 0xF3, 0x3F, 0xEB, 0x13, 0xE6, 0x03, 0xE5, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0x87, 0x03, 0x06, 0x03, 0x44, 0x02, 0x83, 0x01, + 0xE1, 0x00, 0x81, 0x00, 0x61, 0x00, 0x41, 0x00, 0x81, 0x04, 0xC2, 0x04, 0x03, 0x09, 0x24, 0x0D, + 0x45, 0x0D, 0x66, 0x11, 0x65, 0x11, 0x45, 0x0D, 0x45, 0x0D, 0x45, 0x09, 0x45, 0x09, 0x44, 0x05, + 0x44, 0x05, 0x44, 0x09, 0x63, 0x09, 0x63, 0x09, 0x63, 0x09, 0x84, 0x09, 0x84, 0x09, 0x85, 0x09, + 0x85, 0x09, 0x85, 0x05, 0x84, 0x09, 0x64, 0x05, 0x64, 0x05, 0x64, 0x05, 0x84, 0x05, 0x84, 0x05, + 0x85, 0x05, 0x85, 0x05, 0x64, 0x05, 0x64, 0x05, 0x63, 0x05, 0x63, 0x05, 0x83, 0x05, 0xA3, 0x05, + 0x04, 0x06, 0x65, 0x02, 0xC6, 0x02, 0x06, 0x03, 0x27, 0x03, 0x47, 0x03, 0x47, 0x03, 0x67, 0x03, + 0x67, 0x03, 0x86, 0x03, 0x85, 0x03, 0x64, 0x03, 0x86, 0x03, 0x8C, 0x1B, 0xB2, 0x3F, 0xF8, 0x5F, + 0xFB, 0x6B, 0xFD, 0x73, 0x39, 0x00, 0x44, 0x00, 0xFC, 0x6B, 0xF4, 0x43, 0xEC, 0x13, 0xE7, 0x03, + 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0x87, 0x03, 0x05, 0x03, 0x64, 0x02, + 0x83, 0x01, 0x02, 0x01, 0xA1, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0xA2, 0x04, 0xE3, 0x08, + 0x04, 0x09, 0x45, 0x0D, 0x66, 0x11, 0x66, 0x11, 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x09, + 0x65, 0x09, 0x44, 0x09, 0x44, 0x09, 0x43, 0x09, 0x63, 0x09, 0x64, 0x09, 0x64, 0x09, 0x84, 0x09, + 0x85, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, + 0xA5, 0x09, 0xA5, 0x09, 0xA6, 0x09, 0x85, 0x09, 0x64, 0x05, 0x44, 0x05, 0x43, 0x05, 0x22, 0x05, + 0x42, 0x05, 0x83, 0x05, 0x04, 0x02, 0x65, 0x02, 0xE6, 0x02, 0x27, 0x03, 0x47, 0x03, 0x67, 0x03, + 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0x85, 0x03, 0x84, 0x03, 0x86, 0x03, 0xAE, 0x27, 0xD7, 0x57, + 0x3C, 0x00, 0x44, 0x00, 0xFC, 0x6B, 0xF3, 0x3B, 0xEB, 0x0F, 0xE5, 0x03, 0xE5, 0x03, 0xE8, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xA7, 0x03, 0x26, 0x03, 0x84, 0x02, 0xC3, 0x01, 0x22, 0x01, + 0xA1, 0x00, 0x61, 0x00, 0x41, 0x04, 0x82, 0x04, 0xC2, 0x04, 0xE3, 0x08, 0x24, 0x09, 0x45, 0x0D, + 0x65, 0x0D, 0x66, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x85, 0x0D, 0x65, 0x09, 0x65, 0x09, 0x44, 0x09, + 0x44, 0x09, 0x23, 0x09, 0x23, 0x09, 0x23, 0x09, 0x24, 0x09, 0x24, 0x09, 0x44, 0x09, 0x65, 0x09, + 0x85, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, + 0xA6, 0x09, 0xA5, 0x09, 0x85, 0x09, 0x64, 0x09, 0x44, 0x09, 0x23, 0x09, 0x23, 0x09, 0x63, 0x05, + 0xA3, 0x01, 0x04, 0x02, 0x85, 0x02, 0xE6, 0x02, 0x27, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, + 0x87, 0x03, 0x85, 0x03, 0x84, 0x03, 0x87, 0x03, 0xAF, 0x27, 0xF8, 0x5B, 0x3C, 0x00, 0x44, 0x00, + 0xFB, 0x6B, 0xF3, 0x3B, 0xEA, 0x0B, 0xE4, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xE9, 0x03, 0xE9, 0x03, + 0xE9, 0x03, 0xC8, 0x03, 0x46, 0x03, 0xC5, 0x02, 0x03, 0x02, 0x42, 0x01, 0xC2, 0x00, 0x61, 0x04, + 0x62, 0x04, 0x82, 0x08, 0xC3, 0x08, 0x04, 0x09, 0x24, 0x09, 0x44, 0x09, 0x65, 0x0D, 0x85, 0x0D, + 0x86, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x65, 0x09, 0x64, 0x09, 0x44, 0x09, 0x23, 0x09, 0x03, 0x09, + 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x04, 0x03, 0x05, 0x44, 0x05, 0x85, 0x09, + 0xA6, 0x0D, 0xC6, 0x0D, 0xA6, 0x0D, 0x85, 0x0D, 0xA5, 0x0D, 0xA5, 0x09, 0xA5, 0x09, 0xA5, 0x09, + 0xA5, 0x0D, 0xA5, 0x0D, 0x85, 0x0D, 0x64, 0x09, 0x43, 0x09, 0x63, 0x05, 0x83, 0x01, 0xA3, 0x01, + 0x24, 0x02, 0x85, 0x02, 0x06, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA5, 0x03, + 0xA4, 0x03, 0xA7, 0x03, 0xCF, 0x27, 0xF8, 0x57, 0x3C, 0x00, 0x45, 0x00, 0xFC, 0x6F, 0xF4, 0x43, + 0xEC, 0x17, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xC8, 0x03, + 0x67, 0x03, 0x06, 0x03, 0x64, 0x02, 0xA3, 0x01, 0x22, 0x01, 0xA2, 0x04, 0x82, 0x04, 0xA3, 0x08, + 0xE3, 0x08, 0x04, 0x09, 0x24, 0x09, 0x44, 0x09, 0x64, 0x09, 0x65, 0x09, 0x65, 0x0D, 0x65, 0x0D, + 0x65, 0x09, 0x64, 0x09, 0x43, 0x05, 0x43, 0x05, 0x23, 0x05, 0x03, 0x05, 0xE3, 0x04, 0xA3, 0x04, + 0xA2, 0x04, 0x82, 0x04, 0x82, 0x04, 0xC2, 0x04, 0x03, 0x05, 0x45, 0x09, 0xA6, 0x0D, 0xC6, 0x0D, + 0xA6, 0x0D, 0x86, 0x0D, 0xA6, 0x0D, 0xA5, 0x0D, 0xA5, 0x0D, 0xC5, 0x0D, 0xC6, 0x0D, 0xC6, 0x0D, + 0xA6, 0x0D, 0x85, 0x09, 0x64, 0x09, 0x63, 0x05, 0x43, 0x01, 0x63, 0x01, 0xA3, 0x01, 0x24, 0x02, + 0xC6, 0x02, 0x47, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA6, 0x03, 0xA5, 0x03, 0xC7, 0x03, + 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3B, 0x00, 0x45, 0x00, 0xFD, 0x73, 0xF8, 0x57, 0xF2, 0x37, + 0xEE, 0x27, 0xEB, 0x17, 0xEA, 0x0B, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA7, 0x03, + 0x47, 0x03, 0xC6, 0x02, 0x24, 0x02, 0xA3, 0x01, 0x23, 0x01, 0xC2, 0x04, 0xC3, 0x04, 0xE3, 0x04, + 0xE3, 0x08, 0xE3, 0x08, 0x03, 0x09, 0x23, 0x09, 0x23, 0x09, 0x24, 0x09, 0x44, 0x09, 0x44, 0x09, + 0x44, 0x05, 0x43, 0x05, 0x43, 0x05, 0x23, 0x01, 0x02, 0x01, 0xC2, 0x00, 0x82, 0x04, 0x61, 0x04, + 0x41, 0x04, 0x41, 0x04, 0x81, 0x04, 0xC2, 0x04, 0x24, 0x09, 0x65, 0x09, 0x86, 0x0D, 0xA6, 0x0D, + 0xA6, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0xC6, 0x0D, 0xC6, 0x0D, 0xC6, 0x11, 0xC6, 0x11, 0xA6, 0x0D, + 0xA6, 0x09, 0x85, 0x09, 0x64, 0x05, 0x23, 0x05, 0x22, 0x05, 0x63, 0x01, 0xE4, 0x01, 0x85, 0x02, + 0x06, 0x03, 0x67, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xC6, 0x03, 0xC5, 0x03, 0xC7, 0x03, 0xEE, 0x23, + 0xF7, 0x53, 0xFE, 0x7B, 0x3B, 0x00, 0x45, 0x00, 0xFE, 0x7B, 0xFC, 0x6B, 0xF9, 0x5F, 0xF6, 0x4F, + 0xF0, 0x2F, 0xEB, 0x13, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0x87, 0x03, + 0x27, 0x03, 0xA5, 0x02, 0x24, 0x02, 0x83, 0x01, 0x22, 0x01, 0xE2, 0x00, 0xC2, 0x04, 0xA2, 0x04, + 0xA2, 0x04, 0xC2, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0x03, 0x05, 0x03, 0x05, 0x03, 0x01, + 0x23, 0x01, 0x23, 0x01, 0x43, 0x01, 0x22, 0x01, 0xC2, 0x00, 0x81, 0x00, 0x41, 0x00, 0x20, 0x00, + 0x40, 0x04, 0x61, 0x04, 0xA2, 0x04, 0xE3, 0x04, 0x24, 0x09, 0x65, 0x0D, 0x85, 0x0D, 0xA6, 0x11, + 0xC6, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x0D, 0xA6, 0x0D, 0xA6, 0x09, + 0x85, 0x09, 0x65, 0x05, 0x44, 0x05, 0x23, 0x05, 0x63, 0x05, 0xC3, 0x01, 0x44, 0x02, 0xE5, 0x02, + 0x46, 0x03, 0x86, 0x03, 0xC7, 0x03, 0xC6, 0x03, 0xC5, 0x03, 0xC7, 0x03, 0xEE, 0x23, 0xF7, 0x53, + 0xFE, 0x7B, 0x3E, 0x00, 0x42, 0x00, 0xFC, 0x6F, 0xF5, 0x47, 0xED, 0x1B, 0xE7, 0x03, 0xE5, 0x03, + 0xE7, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0xC8, 0x03, 0x87, 0x03, 0x06, 0x03, 0xA5, 0x02, 0x24, 0x02, + 0x83, 0x01, 0x43, 0x01, 0xE2, 0x00, 0xC2, 0x00, 0xC2, 0x04, 0xC2, 0x04, 0xE2, 0x04, 0xE2, 0x04, + 0x02, 0x01, 0x02, 0x01, 0x23, 0x01, 0x23, 0x01, 0x43, 0x01, 0x83, 0x01, 0x83, 0x01, 0x62, 0x01, + 0x02, 0x01, 0xA1, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x04, 0x41, 0x04, 0x81, 0x04, 0xA2, 0x04, + 0x03, 0x09, 0x44, 0x09, 0x85, 0x0D, 0xC6, 0x11, 0xC7, 0x15, 0xC7, 0x15, 0xC7, 0x15, 0xC7, 0x11, + 0xC7, 0x11, 0xA7, 0x0D, 0xA6, 0x09, 0xA6, 0x09, 0x86, 0x09, 0x65, 0x09, 0x44, 0x09, 0x23, 0x09, + 0x43, 0x05, 0xA3, 0x05, 0x24, 0x02, 0xA5, 0x02, 0x26, 0x03, 0x86, 0x03, 0xC7, 0x03, 0xE6, 0x03, + 0xE4, 0x03, 0xC7, 0x03, 0xEE, 0x23, 0xF6, 0x53, 0xFE, 0x7B, 0x3F, 0x00, 0x41, 0x00, 0xF6, 0x4F, + 0xED, 0x1F, 0xE6, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA8, 0x03, + 0x67, 0x03, 0x06, 0x03, 0xA5, 0x02, 0x24, 0x02, 0xC4, 0x01, 0x63, 0x01, 0x23, 0x01, 0x22, 0x01, + 0x42, 0x05, 0x42, 0x05, 0x62, 0x01, 0x63, 0x01, 0x83, 0x01, 0xA4, 0x01, 0xC4, 0x01, 0xE4, 0x01, + 0x04, 0x02, 0x24, 0x02, 0x03, 0x02, 0xA3, 0x01, 0x22, 0x01, 0xC1, 0x00, 0x60, 0x00, 0x40, 0x00, + 0x20, 0x04, 0x61, 0x04, 0xA2, 0x04, 0x03, 0x09, 0x44, 0x0D, 0x85, 0x11, 0xC6, 0x11, 0xC7, 0x15, + 0xC7, 0x15, 0xA7, 0x11, 0xA7, 0x11, 0xA7, 0x11, 0xA7, 0x0D, 0xA6, 0x0D, 0x86, 0x09, 0x65, 0x09, + 0x44, 0x05, 0x24, 0x05, 0x03, 0x09, 0x43, 0x05, 0x83, 0x05, 0xE4, 0x01, 0x85, 0x02, 0x06, 0x03, + 0x66, 0x03, 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xC7, 0x03, 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, + 0x3E, 0x00, 0x42, 0x00, 0xFE, 0x7B, 0xF6, 0x4B, 0xED, 0x1B, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0xA7, 0x03, 0x67, 0x03, 0x46, 0x03, 0x06, 0x03, 0xA5, 0x02, + 0x45, 0x02, 0x05, 0x02, 0xE4, 0x01, 0xC4, 0x01, 0xC3, 0x01, 0xE3, 0x01, 0x04, 0x02, 0x24, 0x02, + 0x45, 0x02, 0x45, 0x02, 0x65, 0x02, 0x85, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0x84, 0x02, 0x44, 0x02, + 0xE3, 0x01, 0x42, 0x01, 0xC1, 0x00, 0x40, 0x00, 0x20, 0x00, 0x41, 0x04, 0xA2, 0x04, 0x24, 0x09, + 0x65, 0x0D, 0xA5, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xA6, 0x11, 0xA7, 0x11, 0xA7, 0x11, 0xA7, 0x11, + 0xC7, 0x11, 0xA6, 0x0D, 0x85, 0x09, 0x44, 0x09, 0x24, 0x05, 0x03, 0x05, 0x03, 0x05, 0x43, 0x05, + 0x83, 0x01, 0xE4, 0x01, 0x65, 0x02, 0xE6, 0x02, 0x66, 0x03, 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, + 0xC7, 0x03, 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3E, 0x00, 0x42, 0x00, 0xFD, 0x73, 0xF4, 0x47, + 0xEC, 0x1B, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC7, 0x03, 0xA7, 0x03, + 0x87, 0x03, 0x67, 0x03, 0x47, 0x03, 0x06, 0x03, 0xE6, 0x02, 0xA6, 0x02, 0x85, 0x02, 0x65, 0x02, + 0x65, 0x02, 0x85, 0x02, 0xA5, 0x02, 0xC6, 0x02, 0xE6, 0x02, 0x06, 0x03, 0x06, 0x03, 0x26, 0x03, + 0x46, 0x03, 0x46, 0x03, 0x26, 0x03, 0xC5, 0x02, 0x64, 0x06, 0xC3, 0x05, 0x02, 0x01, 0x60, 0x00, + 0x20, 0x00, 0x41, 0x04, 0xC3, 0x08, 0x45, 0x0D, 0x86, 0x0D, 0xA6, 0x11, 0xC6, 0x11, 0xC6, 0x11, + 0xA6, 0x11, 0x86, 0x0D, 0x87, 0x0D, 0xA7, 0x11, 0xC7, 0x11, 0xA6, 0x0D, 0x65, 0x0D, 0x24, 0x09, + 0x03, 0x05, 0x02, 0x05, 0x03, 0x05, 0x43, 0x01, 0x84, 0x01, 0xC4, 0x01, 0x45, 0x02, 0xE6, 0x02, + 0x46, 0x03, 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE8, 0x03, 0xEF, 0x23, 0xF7, 0x53, 0xFE, 0x7B, + 0x3E, 0x00, 0x42, 0x00, 0xFD, 0x77, 0xF5, 0x4B, 0xEC, 0x1B, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0xC7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x87, 0x03, 0x47, 0x03, + 0x27, 0x03, 0x06, 0x03, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0x06, 0x03, 0x27, 0x03, + 0x47, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x67, 0x03, 0x06, 0x03, + 0x85, 0x02, 0xC3, 0x05, 0x02, 0x01, 0x61, 0x00, 0x20, 0x00, 0x62, 0x04, 0xE3, 0x08, 0x65, 0x0D, + 0xA6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xA6, 0x11, 0xA7, 0x0D, 0xA7, 0x0D, 0xA7, 0x11, + 0xA6, 0x11, 0x86, 0x0D, 0x44, 0x09, 0x03, 0x09, 0xE2, 0x04, 0xE2, 0x04, 0x02, 0x05, 0x43, 0x05, + 0x83, 0x01, 0xC4, 0x01, 0x45, 0x02, 0xC6, 0x02, 0x46, 0x03, 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, + 0xE8, 0x03, 0xEF, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3F, 0x00, 0x41, 0x00, 0xF6, 0x4F, 0xED, 0x1B, + 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xA7, 0x03, + 0x88, 0x03, 0x87, 0x03, 0x67, 0x03, 0x47, 0x03, 0x26, 0x03, 0x26, 0x03, 0x06, 0x03, 0x06, 0x03, + 0x27, 0x03, 0x27, 0x03, 0x47, 0x03, 0x47, 0x03, 0x67, 0x03, 0x67, 0x03, 0x87, 0x03, 0xA8, 0x03, + 0xA8, 0x03, 0x67, 0x03, 0xE6, 0x02, 0x44, 0x02, 0x83, 0x01, 0xE2, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x82, 0x04, 0x03, 0x09, 0x85, 0x0D, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC7, 0x11, + 0xC7, 0x11, 0xA7, 0x0D, 0xA7, 0x11, 0x86, 0x11, 0x65, 0x0D, 0x24, 0x09, 0x03, 0x05, 0xE2, 0x04, + 0xE2, 0x04, 0x02, 0x05, 0x43, 0x05, 0x63, 0x05, 0xA3, 0x01, 0x24, 0x02, 0xC5, 0x02, 0x46, 0x03, + 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3E, 0x00, + 0x42, 0x00, 0xFE, 0x77, 0xF6, 0x4B, 0xED, 0x1B, 0xE7, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0x88, 0x03, 0x87, 0x03, 0x67, 0x03, 0x46, 0x03, + 0x46, 0x03, 0x26, 0x03, 0x26, 0x03, 0x27, 0x03, 0x27, 0x03, 0x47, 0x03, 0x47, 0x03, 0x47, 0x03, + 0x47, 0x03, 0x67, 0x03, 0x67, 0x03, 0x88, 0x03, 0x88, 0x03, 0x27, 0x03, 0x85, 0x02, 0xE3, 0x01, + 0x22, 0x01, 0xA1, 0x00, 0x61, 0x00, 0x62, 0x04, 0xA3, 0x08, 0x24, 0x09, 0xA5, 0x0D, 0xC5, 0x11, + 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xE7, 0x11, 0xE7, 0x11, 0xC7, 0x11, 0xA7, 0x11, 0x86, 0x11, + 0x45, 0x0D, 0x24, 0x09, 0x03, 0x05, 0xE2, 0x04, 0xE2, 0x04, 0x02, 0x05, 0x43, 0x05, 0x83, 0x05, + 0xC3, 0x01, 0x44, 0x02, 0xC5, 0x02, 0x46, 0x03, 0xC7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3C, 0x00, 0x44, 0x00, 0xFE, 0x77, 0xFC, 0x6B, 0xF8, 0x5B, + 0xF2, 0x3B, 0xEC, 0x17, 0xE7, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0x88, 0x03, 0x67, 0x03, 0x67, 0x03, 0x66, 0x03, 0x46, 0x03, + 0x47, 0x03, 0x47, 0x03, 0x47, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, + 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0xE6, 0x02, 0x44, 0x02, 0x83, 0x01, 0xE2, 0x00, 0xA1, 0x00, + 0x82, 0x04, 0xA3, 0x04, 0xE3, 0x08, 0x44, 0x0D, 0xA5, 0x11, 0xC5, 0x11, 0xC6, 0x11, 0xC6, 0x11, + 0xC7, 0x11, 0xE7, 0x11, 0xE7, 0x11, 0xC7, 0x11, 0xA6, 0x11, 0x66, 0x11, 0x45, 0x0D, 0x04, 0x09, + 0xE3, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0x03, 0x05, 0x43, 0x05, 0x83, 0x05, 0xE4, 0x01, 0x64, 0x02, + 0xE5, 0x02, 0x46, 0x03, 0xA7, 0x03, 0xE6, 0x03, 0xE5, 0x03, 0xE7, 0x03, 0xEE, 0x23, 0xF7, 0x53, + 0xFE, 0x7B, 0x3C, 0x00, 0x44, 0x00, 0xFB, 0x63, 0xF5, 0x47, 0xF1, 0x33, 0xED, 0x1F, 0xEA, 0x0B, + 0xE8, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, + 0xA8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x87, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, + 0x67, 0x03, 0x67, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0x67, 0x03, 0x67, 0x03, + 0x27, 0x03, 0xA5, 0x02, 0x04, 0x02, 0x42, 0x01, 0xC1, 0x00, 0xA1, 0x04, 0xA2, 0x04, 0xE3, 0x04, + 0x24, 0x09, 0x64, 0x0D, 0xA5, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC7, 0x11, 0xC7, 0x11, + 0xC7, 0x11, 0xC7, 0x11, 0xA6, 0x11, 0x66, 0x11, 0x45, 0x0D, 0x24, 0x09, 0xE3, 0x04, 0xE2, 0x04, + 0xE2, 0x04, 0xE3, 0x04, 0x43, 0x05, 0xA4, 0x05, 0x04, 0x06, 0x85, 0x02, 0x06, 0x03, 0x66, 0x03, + 0xA7, 0x03, 0xC6, 0x03, 0xC5, 0x03, 0xC7, 0x03, 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x3B, 0x00, + 0x45, 0x00, 0xFE, 0x77, 0xF6, 0x4F, 0xEF, 0x23, 0xE9, 0x0F, 0xE8, 0x0B, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0xC7, 0x03, 0xC8, 0x03, + 0xC8, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x67, 0x03, 0x67, 0x03, 0x66, 0x03, 0x67, 0x03, + 0x67, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0x87, 0x03, 0x46, 0x03, 0x26, 0x03, 0xE6, 0x02, + 0x44, 0x02, 0xA3, 0x01, 0x22, 0x05, 0xC1, 0x04, 0xC2, 0x04, 0xE2, 0x04, 0x23, 0x05, 0x64, 0x09, + 0x85, 0x0D, 0xA5, 0x11, 0xA6, 0x11, 0xA6, 0x15, 0xA7, 0x11, 0xA7, 0x11, 0xC7, 0x11, 0xC6, 0x11, + 0xA6, 0x11, 0xA6, 0x11, 0x66, 0x11, 0x45, 0x0D, 0x24, 0x09, 0x03, 0x05, 0xE2, 0x04, 0xE2, 0x00, + 0xE3, 0x00, 0x44, 0x01, 0xA4, 0x05, 0x25, 0x06, 0xA6, 0x06, 0x26, 0x03, 0x66, 0x03, 0xA7, 0x03, + 0xC6, 0x03, 0xC5, 0x03, 0xC8, 0x03, 0xCF, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x39, 0x00, 0x47, 0x00, + 0xFE, 0x77, 0xFC, 0x6F, 0xF8, 0x5B, 0xF1, 0x33, 0xEA, 0x07, 0xE5, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x87, 0x03, 0x86, 0x03, + 0x66, 0x03, 0x87, 0x03, 0x87, 0x03, 0x67, 0x03, 0x47, 0x03, 0x26, 0x03, 0xE5, 0x02, 0xA5, 0x02, + 0x64, 0x02, 0xE4, 0x01, 0x63, 0x01, 0x02, 0x05, 0xE2, 0x08, 0xE3, 0x08, 0x23, 0x09, 0x64, 0x09, + 0x85, 0x0D, 0xA5, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0xA7, 0x15, 0xA7, 0x11, 0xA7, 0x11, 0xA6, 0x11, + 0xA6, 0x11, 0xA6, 0x11, 0x85, 0x11, 0x65, 0x0D, 0x45, 0x0D, 0x24, 0x09, 0x03, 0x05, 0x03, 0x05, + 0xE3, 0x04, 0x03, 0x01, 0x44, 0x01, 0xC4, 0x01, 0x45, 0x06, 0xE6, 0x06, 0x46, 0x03, 0x66, 0x03, + 0x87, 0x03, 0xA6, 0x03, 0xA5, 0x03, 0xA7, 0x03, 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x39, 0x00, + 0x47, 0x00, 0xFA, 0x63, 0xF6, 0x4B, 0xF1, 0x37, 0xEC, 0x1B, 0xE8, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC7, 0x03, 0xC7, 0x03, + 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x46, 0x03, 0x06, 0x03, 0xC6, 0x02, 0x65, 0x02, + 0x04, 0x02, 0xE4, 0x01, 0x83, 0x01, 0x43, 0x05, 0x23, 0x05, 0x23, 0x09, 0x24, 0x09, 0x64, 0x09, + 0x85, 0x0D, 0xA5, 0x0D, 0xC6, 0x11, 0xC7, 0x11, 0xA7, 0x11, 0x87, 0x11, 0x87, 0x11, 0x86, 0x11, + 0xA6, 0x11, 0xA6, 0x11, 0xA5, 0x11, 0x65, 0x0D, 0x44, 0x0D, 0x24, 0x09, 0x24, 0x09, 0x24, 0x09, + 0x24, 0x09, 0x03, 0x05, 0x03, 0x05, 0x43, 0x05, 0xC4, 0x01, 0x65, 0x02, 0x06, 0x03, 0x46, 0x03, + 0x66, 0x03, 0x87, 0x03, 0xA6, 0x03, 0xA4, 0x03, 0xA7, 0x03, 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, + 0x38, 0x00, 0x48, 0x00, 0xFE, 0x73, 0xF6, 0x4B, 0xEF, 0x23, 0xE9, 0x13, 0xE8, 0x0B, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC7, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x66, 0x03, 0x06, 0x03, 0xA6, 0x02, + 0x45, 0x02, 0xC4, 0x01, 0x83, 0x01, 0x63, 0x01, 0x43, 0x05, 0x43, 0x05, 0x44, 0x05, 0x65, 0x09, + 0x65, 0x0D, 0x85, 0x0D, 0xA5, 0x11, 0xC6, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xA7, 0x11, 0x87, 0x11, + 0x66, 0x11, 0x86, 0x15, 0xA6, 0x15, 0xA6, 0x11, 0x85, 0x11, 0x64, 0x0D, 0x24, 0x09, 0x23, 0x09, + 0x24, 0x09, 0x44, 0x09, 0x44, 0x09, 0x23, 0x09, 0x23, 0x05, 0x63, 0x05, 0xE4, 0x01, 0x85, 0x02, + 0x06, 0x03, 0x66, 0x03, 0x66, 0x03, 0x87, 0x03, 0xA5, 0x03, 0xA4, 0x03, 0xA7, 0x03, 0xCE, 0x23, + 0xF6, 0x53, 0xFE, 0x7B, 0x36, 0x00, 0x4A, 0x00, 0xFE, 0x77, 0xFD, 0x73, 0xF8, 0x5B, 0xF0, 0x2F, + 0xE9, 0x07, 0xE5, 0x03, 0xE5, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0xC8, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0x86, 0x03, + 0x46, 0x03, 0x06, 0x03, 0x85, 0x02, 0x25, 0x02, 0xC4, 0x01, 0x64, 0x01, 0x23, 0x01, 0x23, 0x05, + 0x23, 0x05, 0x44, 0x05, 0x65, 0x09, 0xA6, 0x0D, 0xA6, 0x0D, 0xA6, 0x11, 0xC6, 0x11, 0xC7, 0x11, + 0xE7, 0x11, 0xE8, 0x11, 0xC8, 0x11, 0x87, 0x11, 0x87, 0x15, 0x86, 0x15, 0x86, 0x11, 0xA6, 0x11, + 0x85, 0x11, 0x44, 0x0D, 0x23, 0x09, 0x03, 0x05, 0x23, 0x09, 0x44, 0x09, 0x44, 0x09, 0x43, 0x09, + 0x63, 0x05, 0xA3, 0x05, 0x24, 0x02, 0xA5, 0x02, 0x26, 0x03, 0x66, 0x03, 0x86, 0x03, 0x87, 0x03, + 0xA5, 0x03, 0xA4, 0x03, 0xA6, 0x03, 0xCE, 0x23, 0xF6, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, + 0xFD, 0x73, 0xF9, 0x5F, 0xF6, 0x4B, 0xF1, 0x37, 0xEC, 0x1B, 0xE8, 0x03, 0xE5, 0x03, 0xE6, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x67, 0x03, + 0x46, 0x03, 0x46, 0x03, 0x66, 0x03, 0x66, 0x03, 0x26, 0x03, 0xE5, 0x02, 0x85, 0x02, 0x04, 0x02, + 0xC4, 0x01, 0x84, 0x01, 0x43, 0x05, 0x23, 0x05, 0x23, 0x05, 0x23, 0x05, 0x44, 0x09, 0x85, 0x0D, + 0xA6, 0x0D, 0xC7, 0x11, 0xC6, 0x11, 0xC6, 0x11, 0xC7, 0x15, 0xE7, 0x15, 0xE8, 0x15, 0xC8, 0x15, + 0xA8, 0x15, 0x87, 0x15, 0x86, 0x15, 0x86, 0x11, 0x85, 0x11, 0x65, 0x0D, 0x44, 0x09, 0x24, 0x09, + 0x03, 0x09, 0x03, 0x09, 0x03, 0x09, 0x43, 0x05, 0x63, 0x05, 0xA3, 0x05, 0x04, 0x02, 0x65, 0x02, + 0xE6, 0x02, 0x47, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA5, 0x03, 0xA4, 0x03, 0xA7, 0x03, + 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFB, 0x67, 0xF5, 0x43, 0xEE, 0x23, + 0xEA, 0x13, 0xE9, 0x0B, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC7, 0x03, 0xA8, 0x03, 0x67, 0x03, 0x27, 0x03, 0x06, 0x03, 0xE5, 0x02, 0xE5, 0x02, 0x05, 0x03, + 0x05, 0x03, 0xC5, 0x02, 0x65, 0x02, 0x04, 0x06, 0xA4, 0x05, 0x64, 0x05, 0x63, 0x05, 0x43, 0x05, + 0x23, 0x05, 0x23, 0x05, 0x44, 0x09, 0x65, 0x0D, 0xA6, 0x0D, 0xC7, 0x11, 0xC7, 0x11, 0xC6, 0x11, + 0xC6, 0x11, 0xC7, 0x15, 0xC8, 0x15, 0xC8, 0x15, 0xC8, 0x15, 0xC8, 0x15, 0xC7, 0x15, 0xA7, 0x11, + 0x86, 0x11, 0x85, 0x0D, 0x64, 0x0D, 0x44, 0x09, 0x24, 0x09, 0x04, 0x09, 0xE3, 0x04, 0xE3, 0x04, + 0x23, 0x05, 0x83, 0x01, 0xE3, 0x01, 0x64, 0x02, 0xC5, 0x02, 0x06, 0x03, 0x47, 0x03, 0x67, 0x03, + 0x87, 0x03, 0x87, 0x03, 0x86, 0x03, 0xA5, 0x03, 0xA7, 0x03, 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, + 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x5F, 0xF1, 0x33, 0xE9, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0xA7, 0x03, 0x67, 0x03, 0x27, 0x03, 0xE6, 0x02, + 0x86, 0x02, 0x65, 0x02, 0x44, 0x02, 0x44, 0x02, 0x64, 0x02, 0x65, 0x02, 0x24, 0x02, 0xE4, 0x05, + 0x84, 0x05, 0x43, 0x05, 0x23, 0x05, 0x23, 0x05, 0x23, 0x05, 0x23, 0x05, 0x44, 0x09, 0x64, 0x09, + 0x85, 0x0D, 0xA6, 0x11, 0xC7, 0x15, 0xC7, 0x15, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x15, + 0xC8, 0x15, 0xC8, 0x15, 0xC8, 0x15, 0xC7, 0x15, 0xA7, 0x11, 0x86, 0x11, 0x65, 0x0D, 0x44, 0x09, + 0x24, 0x09, 0x24, 0x09, 0x03, 0x09, 0xE3, 0x04, 0xE2, 0x04, 0x42, 0x01, 0xA3, 0x01, 0x24, 0x02, + 0xA5, 0x02, 0x06, 0x03, 0x27, 0x03, 0x67, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0x86, 0x03, + 0xA5, 0x03, 0xA7, 0x03, 0xCE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x5F, + 0xF1, 0x2F, 0xE8, 0x03, 0xE4, 0x03, 0xE5, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xC8, 0x03, + 0xA7, 0x03, 0x46, 0x03, 0xE6, 0x02, 0xA6, 0x02, 0x45, 0x02, 0xE5, 0x01, 0xC4, 0x01, 0xC4, 0x01, + 0xA4, 0x01, 0xC4, 0x01, 0xC4, 0x01, 0xA4, 0x05, 0x63, 0x05, 0x43, 0x05, 0x03, 0x09, 0x03, 0x09, + 0x03, 0x09, 0x24, 0x09, 0x44, 0x09, 0x65, 0x09, 0x85, 0x0D, 0xA6, 0x0D, 0xC7, 0x11, 0xC7, 0x11, + 0xC7, 0x11, 0xE7, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xC7, 0x15, 0xC7, 0x15, 0xC7, 0x15, 0xC7, 0x15, + 0xC7, 0x11, 0xA7, 0x11, 0xA6, 0x11, 0x85, 0x0D, 0x45, 0x0D, 0x24, 0x09, 0x04, 0x09, 0x03, 0x05, + 0xE2, 0x04, 0x02, 0x01, 0x62, 0x01, 0xE3, 0x01, 0x65, 0x02, 0xE6, 0x02, 0x26, 0x03, 0x47, 0x03, + 0x67, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA6, 0x03, 0xA5, 0x03, 0xA7, 0x03, 0xCE, 0x23, + 0xF7, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF2, 0x33, 0xEA, 0x07, 0xE6, 0x03, + 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA8, 0x03, 0x87, 0x03, 0x47, 0x03, 0xE6, 0x02, 0x65, 0x02, + 0x05, 0x02, 0xA4, 0x01, 0x64, 0x01, 0x44, 0x05, 0x44, 0x05, 0x43, 0x05, 0x43, 0x05, 0x43, 0x05, + 0x43, 0x05, 0x43, 0x05, 0x23, 0x09, 0x03, 0x09, 0x03, 0x09, 0x03, 0x09, 0x24, 0x09, 0x45, 0x09, + 0x65, 0x09, 0x86, 0x0D, 0xA7, 0x0D, 0xC7, 0x11, 0xC8, 0x11, 0xC8, 0x11, 0xE8, 0x11, 0xC8, 0x11, + 0xC7, 0x11, 0xC7, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0xA7, 0x11, 0xA7, 0x11, 0xA7, 0x11, 0x86, 0x11, + 0x86, 0x0D, 0x65, 0x0D, 0x24, 0x09, 0x03, 0x09, 0x03, 0x05, 0x02, 0x01, 0x22, 0x01, 0x83, 0x01, + 0x04, 0x02, 0x85, 0x02, 0x06, 0x03, 0x46, 0x03, 0x46, 0x03, 0x46, 0x03, 0x66, 0x03, 0x86, 0x03, + 0xA7, 0x03, 0xA5, 0x03, 0xA4, 0x03, 0xA7, 0x03, 0xCE, 0x23, 0xF6, 0x53, 0xFE, 0x7B, 0x35, 0x00, + 0x4B, 0x00, 0xFA, 0x63, 0xF2, 0x37, 0xEA, 0x0B, 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0xA8, 0x03, 0x67, 0x03, + 0x27, 0x03, 0xE6, 0x02, 0xA6, 0x02, 0x45, 0x02, 0xC4, 0x01, 0x64, 0x01, 0x23, 0x01, 0xE3, 0x04, + 0xE3, 0x04, 0xE3, 0x08, 0xE3, 0x08, 0x03, 0x09, 0x03, 0x09, 0x03, 0x09, 0x23, 0x09, 0x23, 0x09, + 0x23, 0x09, 0x03, 0x09, 0x04, 0x09, 0x04, 0x09, 0x25, 0x0D, 0x66, 0x0D, 0x86, 0x0D, 0xA7, 0x0D, + 0xC7, 0x11, 0xC7, 0x11, 0xC8, 0x11, 0xC7, 0x11, 0xC7, 0x11, 0xA7, 0x11, 0xA6, 0x11, 0xA6, 0x0D, + 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x45, 0x0D, 0x24, 0x09, + 0x03, 0x05, 0x02, 0x05, 0x22, 0x01, 0x63, 0x01, 0xE3, 0x01, 0x45, 0x02, 0xC6, 0x02, 0x27, 0x03, + 0x47, 0x03, 0x46, 0x03, 0x46, 0x03, 0x66, 0x03, 0x86, 0x03, 0xA7, 0x03, 0xA5, 0x03, 0xA4, 0x03, + 0xC7, 0x03, 0xCE, 0x23, 0xF6, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF2, 0x37, + 0xEA, 0x0B, 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0x87, 0x03, 0x47, 0x03, 0xE6, 0x02, 0x85, 0x02, 0x45, 0x02, 0x04, 0x02, + 0xC4, 0x01, 0x63, 0x01, 0x23, 0x05, 0x03, 0x05, 0xE3, 0x04, 0xE3, 0x08, 0xE3, 0x08, 0x03, 0x09, + 0x03, 0x09, 0x03, 0x09, 0x04, 0x09, 0x24, 0x09, 0x44, 0x0D, 0x24, 0x0D, 0x04, 0x0D, 0xE3, 0x08, + 0xE3, 0x08, 0x04, 0x09, 0x45, 0x09, 0x66, 0x0D, 0xA6, 0x11, 0xA7, 0x11, 0xC7, 0x11, 0xA7, 0x11, + 0xA6, 0x11, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, 0x86, 0x0D, + 0x66, 0x0D, 0x65, 0x0D, 0x45, 0x0D, 0x24, 0x09, 0x03, 0x09, 0x03, 0x05, 0x22, 0x05, 0x63, 0x01, + 0xC3, 0x01, 0x24, 0x02, 0x85, 0x02, 0xE6, 0x02, 0x27, 0x03, 0x47, 0x03, 0x46, 0x03, 0x66, 0x03, + 0x67, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA6, 0x03, 0xC4, 0x03, 0xC7, 0x03, 0xCE, 0x23, 0xF7, 0x53, + 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF1, 0x37, 0xEA, 0x0B, 0xE5, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE7, 0x03, 0xC7, 0x03, 0xA7, 0x03, 0x26, 0x03, + 0xC5, 0x02, 0x65, 0x02, 0xE4, 0x01, 0x83, 0x01, 0x63, 0x01, 0x43, 0x01, 0x23, 0x05, 0x03, 0x05, + 0x03, 0x09, 0x03, 0x09, 0x23, 0x09, 0x23, 0x09, 0x24, 0x09, 0x24, 0x09, 0x44, 0x09, 0x44, 0x09, + 0x65, 0x0D, 0x65, 0x0D, 0x65, 0x0D, 0x24, 0x0D, 0xE3, 0x08, 0xC3, 0x08, 0xE3, 0x08, 0x04, 0x09, + 0x45, 0x0D, 0x86, 0x11, 0xA6, 0x11, 0xA6, 0x15, 0x86, 0x11, 0x65, 0x0D, 0x45, 0x0D, 0x45, 0x0D, + 0x65, 0x0D, 0x86, 0x11, 0x86, 0x11, 0x86, 0x0D, 0x86, 0x0D, 0x65, 0x0D, 0x45, 0x09, 0x24, 0x09, + 0x03, 0x09, 0x03, 0x09, 0x02, 0x05, 0x63, 0x05, 0xA3, 0x01, 0x24, 0x02, 0x85, 0x02, 0xC5, 0x02, + 0xE6, 0x02, 0x26, 0x03, 0x47, 0x03, 0x47, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA7, 0x03, + 0xA6, 0x03, 0xC5, 0x03, 0xC7, 0x03, 0xEE, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, + 0xFA, 0x63, 0xF1, 0x37, 0xE9, 0x0B, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xC7, 0x03, 0x87, 0x03, 0x46, 0x03, 0xA5, 0x02, 0x24, 0x02, 0xC3, 0x05, 0x42, 0x05, + 0x02, 0x05, 0xE2, 0x00, 0xE2, 0x00, 0xC2, 0x04, 0xE2, 0x08, 0x03, 0x09, 0x03, 0x09, 0x23, 0x09, + 0x43, 0x09, 0x44, 0x09, 0x64, 0x09, 0x64, 0x09, 0x85, 0x09, 0xA6, 0x0D, 0xA6, 0x11, 0x86, 0x0D, + 0x24, 0x0D, 0xE3, 0x08, 0xC2, 0x04, 0xC3, 0x04, 0xE3, 0x08, 0x24, 0x0D, 0x65, 0x0D, 0x86, 0x11, + 0xA6, 0x11, 0x85, 0x11, 0x44, 0x0D, 0x24, 0x09, 0x24, 0x09, 0x45, 0x0D, 0x65, 0x0D, 0x66, 0x0D, + 0x65, 0x0D, 0x65, 0x0D, 0x44, 0x09, 0x24, 0x09, 0x03, 0x05, 0x02, 0x05, 0x22, 0x05, 0x42, 0x05, + 0xA3, 0x05, 0x04, 0x02, 0x65, 0x02, 0xC5, 0x02, 0xE5, 0x02, 0x05, 0x03, 0x26, 0x03, 0x46, 0x03, + 0x47, 0x03, 0x67, 0x03, 0x87, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA6, 0x03, 0xC5, 0x03, 0xC8, 0x03, + 0xEF, 0x23, 0xF7, 0x53, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF1, 0x37, 0xEA, 0x0B, + 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xA7, 0x03, 0x46, 0x03, + 0xC5, 0x02, 0x24, 0x02, 0xA3, 0x01, 0x42, 0x05, 0xE2, 0x04, 0xA2, 0x04, 0xA2, 0x04, 0xA2, 0x04, + 0xA2, 0x04, 0xA2, 0x04, 0xC2, 0x04, 0xC2, 0x04, 0xE3, 0x04, 0x03, 0x05, 0x44, 0x09, 0x65, 0x09, + 0x85, 0x0D, 0xA6, 0x0D, 0xA6, 0x11, 0xA7, 0x11, 0x86, 0x11, 0x45, 0x0D, 0x04, 0x09, 0xE3, 0x08, + 0xC3, 0x08, 0xE4, 0x08, 0x04, 0x09, 0x45, 0x0D, 0x85, 0x11, 0x85, 0x11, 0x85, 0x0D, 0x44, 0x09, + 0x24, 0x09, 0x24, 0x09, 0x44, 0x09, 0x45, 0x0D, 0x45, 0x0D, 0x44, 0x0D, 0x24, 0x0D, 0x23, 0x09, + 0x03, 0x05, 0x03, 0x05, 0x22, 0x01, 0x62, 0x01, 0xA3, 0x05, 0x04, 0x02, 0x65, 0x02, 0xA5, 0x02, + 0x06, 0x03, 0x06, 0x03, 0x05, 0x03, 0x26, 0x03, 0x26, 0x03, 0x47, 0x03, 0x67, 0x03, 0x87, 0x03, + 0x87, 0x03, 0xA7, 0x03, 0xC5, 0x03, 0xC4, 0x03, 0xC6, 0x03, 0xED, 0x1F, 0xF6, 0x4F, 0xFE, 0x7B, + 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF2, 0x37, 0xEA, 0x0B, 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0x87, 0x03, 0x06, 0x03, 0x65, 0x02, 0xC3, 0x01, 0x42, 0x01, + 0x02, 0x05, 0xC2, 0x08, 0xA2, 0x08, 0xA2, 0x04, 0x82, 0x04, 0x82, 0x04, 0x61, 0x04, 0x81, 0x04, + 0x81, 0x00, 0xA2, 0x04, 0xC3, 0x04, 0x04, 0x09, 0x45, 0x0D, 0x86, 0x0D, 0xA6, 0x11, 0xC6, 0x11, + 0xA6, 0x11, 0x86, 0x0D, 0x65, 0x0D, 0x25, 0x09, 0x04, 0x09, 0xE4, 0x08, 0xE4, 0x08, 0x04, 0x09, + 0x45, 0x0D, 0x65, 0x0D, 0x85, 0x0D, 0x85, 0x0D, 0x64, 0x09, 0x44, 0x09, 0x44, 0x09, 0x44, 0x09, + 0x24, 0x09, 0x23, 0x09, 0x03, 0x09, 0x03, 0x09, 0x02, 0x09, 0x02, 0x05, 0x22, 0x01, 0x63, 0x01, + 0xC3, 0x01, 0x04, 0x02, 0x64, 0x02, 0xA5, 0x02, 0xC6, 0x02, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, + 0x26, 0x03, 0x26, 0x03, 0x46, 0x03, 0x66, 0x03, 0x87, 0x03, 0xA7, 0x03, 0xA7, 0x03, 0xC5, 0x03, + 0xC2, 0x03, 0xC4, 0x03, 0xEC, 0x1B, 0xF6, 0x4B, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, + 0xF2, 0x37, 0xEA, 0x0B, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, + 0x67, 0x03, 0xC6, 0x02, 0x04, 0x02, 0x62, 0x01, 0x02, 0x01, 0xC2, 0x04, 0xA2, 0x08, 0x82, 0x08, + 0xA2, 0x08, 0x82, 0x04, 0x61, 0x04, 0x40, 0x00, 0x40, 0x00, 0x41, 0x00, 0x62, 0x00, 0xA3, 0x04, + 0xE4, 0x08, 0x25, 0x0D, 0x66, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0x86, 0x11, 0x66, 0x0D, + 0x45, 0x0D, 0x25, 0x09, 0x05, 0x09, 0x04, 0x09, 0x04, 0x09, 0x24, 0x09, 0x45, 0x09, 0x65, 0x0D, + 0x64, 0x09, 0x64, 0x09, 0x44, 0x09, 0x43, 0x05, 0x43, 0x05, 0x23, 0x05, 0x03, 0x05, 0x02, 0x05, + 0xE2, 0x04, 0x02, 0x05, 0x22, 0x05, 0x63, 0x01, 0xC3, 0x01, 0x24, 0x02, 0x64, 0x02, 0xA5, 0x02, + 0xC6, 0x02, 0xE6, 0x02, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x26, 0x03, 0x46, 0x03, + 0x66, 0x03, 0x86, 0x03, 0xA7, 0x03, 0xC7, 0x03, 0xC5, 0x03, 0xC4, 0x03, 0xC6, 0x03, 0xEE, 0x23, + 0xF6, 0x4F, 0xFE, 0x7B, 0x35, 0x00, 0x4B, 0x00, 0xFA, 0x63, 0xF2, 0x37, 0xEA, 0x0B, 0xE6, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0x47, 0x03, 0x85, 0x02, 0xC3, 0x01, + 0x02, 0x01, 0xA1, 0x00, 0x81, 0x04, 0x61, 0x04, 0x61, 0x08, 0x62, 0x04, 0x62, 0x04, 0x41, 0x04, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x62, 0x04, 0xA3, 0x04, 0xE4, 0x08, 0x25, 0x0D, 0x45, 0x0D, + 0x86, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0xA6, 0x11, 0x86, 0x11, 0x66, 0x0D, 0x45, 0x0D, 0x25, 0x09, + 0x04, 0x09, 0x04, 0x09, 0x24, 0x09, 0x24, 0x09, 0x44, 0x09, 0x44, 0x09, 0x44, 0x09, 0x23, 0x05, + 0x23, 0x05, 0x23, 0x05, 0x22, 0x05, 0x22, 0x05, 0x22, 0x05, 0x43, 0x05, 0x63, 0x05, 0x83, 0x01, + 0xC3, 0x01, 0x24, 0x02, 0x64, 0x02, 0xA5, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, + 0x06, 0x03, 0x06, 0x03, 0x05, 0x03, 0x25, 0x03, 0x45, 0x03, 0x65, 0x03, 0x85, 0x03, 0x85, 0x03, + 0xA6, 0x03, 0xC7, 0x07, 0xC9, 0x17, 0xED, 0x23, 0xF3, 0x3F, 0xF9, 0x5F, 0xFF, 0x7B, 0x35, 0x00, + 0x4A, 0x00, 0xFA, 0x63, 0xF2, 0x37, 0xEA, 0x0B, 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xE8, 0x03, 0xC8, 0x03, 0x46, 0x03, 0x65, 0x02, 0xA3, 0x01, 0xE1, 0x00, 0x81, 0x00, 0x60, 0x04, + 0x40, 0x04, 0x21, 0x04, 0x41, 0x04, 0x41, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x04, + 0x82, 0x04, 0xC4, 0x08, 0x04, 0x0D, 0x04, 0x0D, 0x24, 0x0D, 0x65, 0x0D, 0x85, 0x11, 0xA6, 0x11, + 0xA6, 0x11, 0xA6, 0x11, 0x86, 0x11, 0x45, 0x0D, 0x25, 0x09, 0x24, 0x09, 0x04, 0x09, 0x04, 0x09, + 0x24, 0x09, 0x24, 0x09, 0x04, 0x09, 0x03, 0x05, 0x02, 0x05, 0x02, 0x05, 0x02, 0x05, 0x22, 0x05, + 0x43, 0x05, 0x63, 0x05, 0xA4, 0x01, 0xE4, 0x01, 0x04, 0x02, 0x44, 0x02, 0x84, 0x02, 0xA5, 0x02, + 0xC6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0xE6, 0x02, 0x06, 0x03, 0x05, 0x03, + 0x25, 0x03, 0x24, 0x03, 0x44, 0x03, 0x63, 0x03, 0x82, 0x03, 0xA4, 0x03, 0xC9, 0x13, 0xCF, 0x33, + 0xF6, 0x4F, 0xF9, 0x5F, 0xFC, 0x6F, 0x36, 0x00, 0x49, 0x00, 0xFA, 0x63, 0xF2, 0x37, 0xEA, 0x0B, + 0xE6, 0x03, 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC7, 0x03, 0x46, 0x03, 0x65, 0x02, + 0xA3, 0x01, 0xE2, 0x00, 0x81, 0x00, 0x61, 0x04, 0x40, 0x04, 0x40, 0x04, 0x60, 0x00, 0x61, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x01, 0x04, 0x42, 0x04, 0xA3, 0x08, 0xE4, 0x0C, 0x04, 0x0D, 0x04, 0x09, + 0x04, 0x09, 0x24, 0x0D, 0x65, 0x11, 0x86, 0x11, 0xA6, 0x15, 0x86, 0x11, 0x65, 0x0D, 0x45, 0x0D, + 0x24, 0x09, 0x04, 0x09, 0x03, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x03, 0x09, 0xE3, 0x04, + 0xE2, 0x04, 0x02, 0x05, 0x22, 0x05, 0x62, 0x05, 0xA3, 0x05, 0xC4, 0x01, 0x05, 0x02, 0x45, 0x02, + 0x65, 0x02, 0x85, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC5, 0x02, + 0xE5, 0x02, 0xE5, 0x02, 0xE5, 0x02, 0x06, 0x03, 0x26, 0x03, 0x46, 0x03, 0x66, 0x03, 0x65, 0x03, + 0x83, 0x03, 0xA6, 0x03, 0xCE, 0x27, 0xF6, 0x53, 0xFE, 0x77, 0xFF, 0x7B, 0x37, 0x00, 0x47, 0x00, + 0xFA, 0x63, 0xF1, 0x33, 0xEA, 0x07, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x03, + 0xC8, 0x03, 0x46, 0x03, 0xA5, 0x02, 0x04, 0x02, 0x43, 0x01, 0x02, 0x01, 0xE1, 0x00, 0xA1, 0x00, + 0xA1, 0x00, 0xA1, 0x00, 0xA1, 0x00, 0x61, 0x00, 0x21, 0x00, 0x21, 0x04, 0x42, 0x04, 0x83, 0x08, + 0xC4, 0x08, 0x04, 0x09, 0x03, 0x09, 0x03, 0x09, 0x24, 0x09, 0x44, 0x0D, 0x65, 0x11, 0x65, 0x11, + 0x65, 0x0D, 0x44, 0x0D, 0x24, 0x09, 0x03, 0x09, 0xE3, 0x08, 0xE3, 0x08, 0xE3, 0x08, 0x03, 0x09, + 0x03, 0x05, 0x23, 0x05, 0x23, 0x05, 0x43, 0x01, 0x63, 0x01, 0x83, 0x01, 0xC3, 0x01, 0x04, 0x02, + 0x25, 0x02, 0x65, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC6, 0x02, + 0xC6, 0x02, 0xC6, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC4, 0x02, 0xE4, 0x02, 0x05, 0x03, 0x28, 0x0B, + 0x4B, 0x17, 0x8D, 0x1F, 0x8C, 0x1F, 0xAA, 0x1F, 0xAD, 0x23, 0xD4, 0x43, 0xFB, 0x6B, 0x39, 0x00, + 0x47, 0x00, 0xF9, 0x5F, 0xF1, 0x2F, 0xE8, 0x03, 0xE4, 0x03, 0xE5, 0x03, 0xE8, 0x03, 0xE9, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0x87, 0x03, 0xE6, 0x02, 0x65, 0x02, 0xC4, 0x01, 0x83, 0x01, 0x63, 0x01, + 0x42, 0x01, 0x22, 0x01, 0x02, 0x01, 0xE2, 0x00, 0xA1, 0x00, 0x61, 0x00, 0x21, 0x00, 0x42, 0x04, + 0x62, 0x04, 0xA3, 0x04, 0xE3, 0x08, 0x03, 0x09, 0x23, 0x09, 0x24, 0x09, 0x45, 0x0D, 0x45, 0x0D, + 0x25, 0x0D, 0x24, 0x09, 0x03, 0x09, 0xE3, 0x08, 0xC3, 0x08, 0xC3, 0x08, 0xC3, 0x04, 0xE2, 0x04, + 0x03, 0x05, 0x23, 0x05, 0x43, 0x01, 0x83, 0x01, 0xA4, 0x01, 0xE4, 0x01, 0x04, 0x02, 0x24, 0x02, + 0x44, 0x02, 0x65, 0x02, 0x85, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, + 0xC5, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC5, 0x02, 0xC3, 0x02, 0xC2, 0x02, 0xE5, 0x02, + 0x2B, 0x17, 0x91, 0x37, 0xD6, 0x4B, 0xD5, 0x4B, 0xD4, 0x4B, 0xD5, 0x4F, 0xF9, 0x5F, 0xFE, 0x77, + 0x39, 0x00, 0x46, 0x00, 0xFA, 0x5F, 0xF1, 0x33, 0xE9, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE8, 0x03, + 0xE9, 0x03, 0xE9, 0x03, 0xE8, 0x03, 0xA8, 0x03, 0x47, 0x03, 0xE6, 0x02, 0x65, 0x02, 0x25, 0x02, + 0x04, 0x02, 0xC3, 0x01, 0xA3, 0x01, 0x83, 0x01, 0x42, 0x01, 0xE2, 0x00, 0x82, 0x00, 0x41, 0x00, + 0x41, 0x00, 0x42, 0x00, 0x82, 0x04, 0xA3, 0x04, 0xE3, 0x08, 0x24, 0x09, 0x44, 0x09, 0x24, 0x09, + 0x25, 0x09, 0x04, 0x09, 0xC3, 0x04, 0xC2, 0x04, 0xA2, 0x04, 0x82, 0x04, 0x82, 0x04, 0xA2, 0x04, + 0xE2, 0x04, 0x02, 0x01, 0x63, 0x01, 0xA3, 0x01, 0xE4, 0x01, 0x25, 0x02, 0x65, 0x02, 0x65, 0x02, + 0x85, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC3, 0x02, 0xC3, 0x02, + 0xE7, 0x02, 0x4F, 0x2B, 0xB8, 0x57, 0xFD, 0x77, 0xFD, 0x77, 0xFD, 0x77, 0xFD, 0x77, 0xFE, 0x7B, + 0x3A, 0x00, 0x41, 0x00, 0xFB, 0x67, 0xF5, 0x43, 0xEE, 0x23, 0xEA, 0x13, 0xE9, 0x0B, 0xE8, 0x03, + 0xE7, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xC8, 0x03, 0x88, 0x03, 0x47, 0x03, 0xE6, 0x02, 0xC6, 0x02, + 0xA5, 0x02, 0x64, 0x02, 0x24, 0x02, 0x04, 0x02, 0xC3, 0x01, 0x42, 0x01, 0xE2, 0x00, 0x81, 0x00, + 0x41, 0x00, 0x42, 0x00, 0x62, 0x00, 0xA2, 0x04, 0xE3, 0x04, 0x03, 0x05, 0x24, 0x09, 0x04, 0x09, + 0xE4, 0x08, 0xC3, 0x04, 0xA2, 0x04, 0x82, 0x04, 0x81, 0x04, 0x81, 0x04, 0x82, 0x04, 0xC2, 0x04, + 0x02, 0x01, 0x63, 0x01, 0xC3, 0x01, 0x04, 0x02, 0x45, 0x02, 0x85, 0x02, 0xA6, 0x02, 0xC5, 0x02, + 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0xA4, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xC6, 0x02, 0xE6, 0x0A, 0xE8, 0x12, + 0x2D, 0x23, 0x95, 0x4B, 0xDD, 0x73, 0x3F, 0x00, 0x41, 0x00, 0xFD, 0x73, 0xF9, 0x5F, 0xF6, 0x4B, + 0xF1, 0x37, 0xEC, 0x1B, 0xE8, 0x03, 0xE5, 0x03, 0xE6, 0x03, 0xE7, 0x03, 0xC8, 0x03, 0xA7, 0x03, + 0x67, 0x03, 0x46, 0x03, 0x06, 0x03, 0xE6, 0x02, 0xA5, 0x02, 0x85, 0x02, 0x64, 0x02, 0x04, 0x02, + 0x83, 0x01, 0x02, 0x01, 0xA1, 0x00, 0x61, 0x00, 0x42, 0x00, 0x62, 0x04, 0x82, 0x04, 0xA2, 0x04, + 0xE2, 0x04, 0xE3, 0x04, 0xE3, 0x04, 0xC3, 0x08, 0xA3, 0x04, 0x82, 0x04, 0x61, 0x04, 0x61, 0x00, + 0x81, 0x00, 0xA1, 0x04, 0xE2, 0x00, 0x43, 0x01, 0xA3, 0x01, 0x24, 0x02, 0x65, 0x02, 0x85, 0x02, + 0xA5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA4, 0x02, 0x84, 0x02, 0x83, 0x02, 0x82, 0x02, 0x81, 0x02, 0x81, 0x02, + 0xC5, 0x02, 0x0A, 0x1B, 0x4F, 0x37, 0x95, 0x4B, 0xBA, 0x63, 0xFE, 0x7B, 0x40, 0x00, 0x3F, 0x00, + 0xFE, 0x77, 0xFD, 0x73, 0xF8, 0x5B, 0xF1, 0x2F, 0xE9, 0x07, 0xE5, 0x03, 0xE5, 0x03, 0xE7, 0x03, + 0xC7, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x66, 0x03, 0x46, 0x03, 0x26, 0x03, 0xE5, 0x02, 0xC5, 0x02, + 0xA5, 0x02, 0x44, 0x02, 0xC3, 0x01, 0x42, 0x01, 0xE1, 0x00, 0x81, 0x00, 0x82, 0x00, 0x82, 0x04, + 0x82, 0x04, 0xA2, 0x04, 0xC2, 0x04, 0xC2, 0x04, 0xC3, 0x04, 0xC3, 0x08, 0xA3, 0x04, 0x82, 0x04, + 0x81, 0x04, 0x81, 0x00, 0xA1, 0x00, 0xC2, 0x00, 0x22, 0x01, 0xA3, 0x01, 0x04, 0x02, 0x65, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xC6, 0x02, 0xC6, 0x02, 0xC6, 0x02, + 0xA6, 0x02, 0xA6, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xA3, 0x02, + 0x81, 0x02, 0x81, 0x02, 0xC6, 0x06, 0x2E, 0x2F, 0xB7, 0x5B, 0xFD, 0x73, 0xFE, 0x77, 0x43, 0x00, + 0x3B, 0x00, 0xFE, 0x73, 0xF6, 0x4B, 0xEF, 0x23, 0xE9, 0x13, 0xE7, 0x0B, 0xE7, 0x03, 0xC6, 0x03, + 0xC6, 0x03, 0xA7, 0x03, 0x87, 0x03, 0x66, 0x03, 0x46, 0x03, 0x06, 0x03, 0xE5, 0x02, 0xC5, 0x02, + 0x64, 0x02, 0x04, 0x02, 0xA3, 0x01, 0x42, 0x01, 0xE2, 0x00, 0xC2, 0x00, 0xC2, 0x04, 0xC2, 0x04, + 0xC2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x04, 0xC2, 0x04, 0xA2, 0x04, 0x82, 0x04, 0x81, 0x00, + 0xA1, 0x00, 0xC1, 0x00, 0x02, 0x01, 0x83, 0x01, 0xE4, 0x01, 0x65, 0x02, 0xA6, 0x02, 0xC6, 0x02, + 0xC5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA6, 0x02, 0xA6, 0x02, 0xA6, 0x02, + 0xA5, 0x02, 0x84, 0x02, 0x84, 0x02, 0xA5, 0x02, 0xC7, 0x0A, 0xE9, 0x12, 0xE9, 0x16, 0xC7, 0x16, + 0xC7, 0x16, 0x0C, 0x23, 0x74, 0x4B, 0xFD, 0x73, 0x46, 0x00, 0x39, 0x00, 0xFA, 0x63, 0xF6, 0x4B, + 0xF0, 0x37, 0xEB, 0x1B, 0xC7, 0x03, 0xC4, 0x03, 0xA5, 0x03, 0x86, 0x03, 0x67, 0x03, 0x47, 0x03, + 0x26, 0x03, 0x05, 0x03, 0xE5, 0x02, 0xC5, 0x02, 0x84, 0x02, 0x24, 0x02, 0xE3, 0x01, 0x83, 0x01, + 0x42, 0x01, 0x22, 0x01, 0x02, 0x01, 0x02, 0x01, 0x23, 0x01, 0x23, 0x01, 0x23, 0x01, 0x03, 0x01, + 0xE2, 0x04, 0xC2, 0x04, 0xA1, 0x00, 0x81, 0x00, 0xA1, 0x00, 0xE2, 0x00, 0x43, 0x01, 0xC4, 0x01, + 0x24, 0x02, 0x65, 0x02, 0xA5, 0x02, 0xC5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA5, 0x02, 0x84, 0x02, 0x62, 0x02, 0x62, 0x02, 0xA5, 0x02, + 0xEB, 0x1E, 0x51, 0x37, 0x52, 0x43, 0x51, 0x43, 0x51, 0x43, 0x74, 0x4B, 0xB9, 0x63, 0x47, 0x00, + 0x39, 0x00, 0xFE, 0x77, 0xFC, 0x6F, 0xF8, 0x5B, 0xF0, 0x33, 0xC9, 0x07, 0xA4, 0x03, 0xA4, 0x03, + 0x86, 0x03, 0x47, 0x03, 0x26, 0x03, 0x06, 0x03, 0xE5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0x84, 0x02, + 0x44, 0x02, 0x24, 0x02, 0xE3, 0x01, 0xA3, 0x01, 0x83, 0x01, 0x63, 0x01, 0x63, 0x01, 0x83, 0x01, + 0xA4, 0x01, 0x84, 0x01, 0x43, 0x01, 0x22, 0x01, 0xE2, 0x00, 0xC1, 0x00, 0xA1, 0x00, 0xC2, 0x00, + 0x22, 0x01, 0x83, 0x01, 0xE4, 0x01, 0x45, 0x02, 0x65, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0x83, 0x02, + 0x61, 0x02, 0x61, 0x02, 0xC7, 0x0E, 0x30, 0x37, 0xB9, 0x5F, 0xDB, 0x6B, 0xDB, 0x6B, 0xDB, 0x6B, + 0xDC, 0x6F, 0xFD, 0x77, 0x49, 0x00, 0x32, 0x00, 0xFE, 0x77, 0xF6, 0x4F, 0xEE, 0x23, 0xA9, 0x0F, + 0x87, 0x07, 0x67, 0x03, 0x26, 0x03, 0x05, 0x03, 0xE5, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0x85, 0x02, 0x65, 0x02, 0x64, 0x02, 0x44, 0x02, 0x24, 0x02, 0x03, 0x02, 0xE3, 0x01, 0xE4, 0x01, + 0xE4, 0x01, 0x04, 0x02, 0xE4, 0x01, 0xA3, 0x01, 0x83, 0x01, 0x42, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x22, 0x01, 0x63, 0x01, 0xC4, 0x01, 0x25, 0x02, 0x65, 0x02, 0x85, 0x02, 0xA4, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA4, 0x02, 0x84, 0x02, 0xA4, 0x02, + 0xA4, 0x02, 0x84, 0x0A, 0xA6, 0x0E, 0x0D, 0x27, 0x96, 0x53, 0xFE, 0x7B, 0x4F, 0x00, 0x30, 0x00, + 0xFB, 0x63, 0xF5, 0x47, 0xD0, 0x33, 0x8B, 0x1B, 0x47, 0x03, 0x03, 0x03, 0xE2, 0x02, 0xC3, 0x02, + 0xA3, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0x85, 0x02, 0x85, 0x02, 0x85, 0x02, 0x65, 0x02, + 0x44, 0x02, 0x24, 0x02, 0x24, 0x02, 0x24, 0x02, 0x24, 0x02, 0x04, 0x02, 0xE4, 0x01, 0xC3, 0x01, + 0x82, 0x01, 0x62, 0x01, 0x62, 0x01, 0x83, 0x01, 0xC3, 0x01, 0x04, 0x02, 0x45, 0x02, 0x65, 0x02, + 0x85, 0x02, 0x84, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0x84, 0x02, 0x84, 0x02, 0x83, 0x02, + 0x82, 0x02, 0x61, 0x02, 0x82, 0x02, 0xA6, 0x06, 0xE9, 0x1E, 0x2F, 0x37, 0x74, 0x4B, 0xBA, 0x67, + 0x50, 0x00, 0x30, 0x00, 0xFE, 0x77, 0xFC, 0x6B, 0xD8, 0x5B, 0x90, 0x33, 0x48, 0x0B, 0xE2, 0x02, + 0xC1, 0x02, 0xC3, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, + 0xA5, 0x02, 0x86, 0x02, 0x65, 0x02, 0x65, 0x02, 0x45, 0x02, 0x65, 0x02, 0x64, 0x02, 0x44, 0x02, + 0x24, 0x02, 0x03, 0x02, 0xE3, 0x01, 0xC3, 0x01, 0xC3, 0x01, 0xC3, 0x01, 0x04, 0x02, 0x24, 0x02, + 0x64, 0x02, 0x64, 0x02, 0x85, 0x02, 0x85, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA5, 0x02, 0xA4, 0x02, + 0x84, 0x02, 0x83, 0x02, 0x82, 0x02, 0x61, 0x02, 0x82, 0x02, 0xC8, 0x0E, 0x30, 0x37, 0x98, 0x5F, + 0xDB, 0x6F, 0xFD, 0x77, 0x52, 0x00, 0x2B, 0x00, 0xFE, 0x7B, 0xB6, 0x4F, 0x6D, 0x23, 0x06, 0x0B, + 0x05, 0x0B, 0xE7, 0x0A, 0xE8, 0x0A, 0xC7, 0x06, 0xC6, 0x02, 0xC5, 0x02, 0xA5, 0x02, 0xC5, 0x02, + 0xA6, 0x02, 0xA6, 0x02, 0x86, 0x02, 0x85, 0x02, 0x85, 0x02, 0x85, 0x02, 0x84, 0x02, 0x64, 0x02, + 0x64, 0x02, 0x44, 0x02, 0x24, 0x02, 0x24, 0x02, 0x24, 0x02, 0x24, 0x02, 0x44, 0x02, 0x44, 0x02, + 0x64, 0x02, 0x84, 0x02, 0x84, 0x02, 0x84, 0x02, 0x84, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xC6, 0x02, + 0xC7, 0x06, 0xC8, 0x0A, 0xC7, 0x0A, 0xA5, 0x0A, 0xC7, 0x0A, 0x0E, 0x2B, 0x97, 0x57, 0x56, 0x00, + 0x2A, 0x00, 0xDA, 0x67, 0x94, 0x47, 0x6F, 0x37, 0x4F, 0x37, 0x50, 0x37, 0x50, 0x33, 0x0C, 0x1F, + 0xE7, 0x06, 0xA3, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA3, 0x02, 0x84, 0x02, 0x84, 0x02, 0x84, 0x02, + 0x64, 0x02, 0x63, 0x02, 0x63, 0x02, 0x63, 0x02, 0x43, 0x02, 0x43, 0x02, 0x43, 0x02, 0x22, 0x02, + 0x23, 0x02, 0x23, 0x02, 0x43, 0x02, 0x43, 0x02, 0x63, 0x02, 0x63, 0x02, 0x63, 0x02, 0x62, 0x02, + 0x62, 0x02, 0x81, 0x02, 0xA3, 0x02, 0xC7, 0x0A, 0x0C, 0x23, 0x50, 0x33, 0x30, 0x37, 0x2F, 0x37, + 0x30, 0x37, 0x75, 0x4B, 0xDB, 0x6B, 0x56, 0x00, 0x2A, 0x00, 0xFD, 0x77, 0xDB, 0x6B, 0xD9, 0x63, + 0xB9, 0x63, 0xB9, 0x63, 0xB8, 0x5F, 0x71, 0x3B, 0x09, 0x13, 0xC3, 0x02, 0xA0, 0x02, 0xA1, 0x02, + 0x82, 0x02, 0x82, 0x02, 0x62, 0x02, 0x63, 0x02, 0x43, 0x02, 0x63, 0x02, 0x62, 0x02, 0x42, 0x02, + 0x42, 0x02, 0x42, 0x02, 0x42, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x42, 0x02, 0x42, 0x02, + 0x42, 0x02, 0x42, 0x02, 0x42, 0x02, 0x62, 0x02, 0x60, 0x02, 0x60, 0x02, 0xA2, 0x02, 0x0A, 0x17, + 0x52, 0x3F, 0xB9, 0x5F, 0xB9, 0x63, 0xB9, 0x63, 0xB9, 0x63, 0xDB, 0x6B, 0xFE, 0x77, 0x5C, 0x00, + 0x1E, 0x00, 0xB7, 0x57, 0x4F, 0x2B, 0xE7, 0x06, 0xC4, 0x06, 0xC5, 0x06, 0xC6, 0x06, 0xA6, 0x06, + 0xA6, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, + 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x87, 0x06, 0x86, 0x06, + 0x86, 0x06, 0xA6, 0x06, 0xA4, 0x06, 0xA3, 0x06, 0xE7, 0x0A, 0x4F, 0x2F, 0xB8, 0x5B, 0x62, 0x00, + 0x1E, 0x00, 0xDB, 0x6B, 0x95, 0x4B, 0x4F, 0x2F, 0x2D, 0x2F, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, + 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, + 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, 0x0F, 0x2F, + 0x0F, 0x2F, 0x0E, 0x2F, 0x0D, 0x2F, 0x0C, 0x2F, 0x4F, 0x33, 0x95, 0x4F, 0xDC, 0x6F, 0x62, 0x00, + 0x1E, 0x00, 0xFE, 0x77, 0xDB, 0x67, 0xB8, 0x5F, 0xB7, 0x5F, 0xB8, 0x5F, 0xB8, 0x5F, 0x98, 0x5F, + 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, + 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, 0x98, 0x5F, + 0x98, 0x5F, 0x98, 0x5F, 0x97, 0x5F, 0x97, 0x5F, 0xB8, 0x5F, 0xDB, 0x6B, 0xFE, 0x7B, 0x3F, 0x08, + 0x00, 0x00 +}; + + diff --git a/backends/platform/ps2/iop/CoDyVDfs/Makefile b/backends/platform/ps2/iop/CoDyVDfs/Makefile new file mode 100644 index 0000000000..4493e77154 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/Makefile @@ -0,0 +1,30 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ + + +IOP_OBJS_DIR = obj/ +IOP_BIN_DIR = bin/ +IOP_SRC_DIR = iop/ +IOP_INC_DIR = include/ + +IOP_BIN = iop/CoDyVDfs.irx +IOP_OBJS = obj/codyvdfs.o obj/fiofs.o obj/rpcfs.o obj/imports.o + +IOP_CFLAGS += -Wall -fno-builtin +IOP_LDFLAGS += -s + +all: $(IOP_OBJS_DIR) $(IOP_BIN_DIR) $(IOP_BIN) + +clean: + rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN_DIR) + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/backends/platform/ps2/iop/CoDyVDfs/common/codyvdirx.h b/backends/platform/ps2/iop/CoDyVDfs/common/codyvdirx.h new file mode 100644 index 0000000000..6b81d000ae --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/common/codyvdirx.h @@ -0,0 +1,38 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef CDVDFS_COMMON_H +#define CDVDFS_COMMON_H + +#define CDVDFS_IRX_ID 0xD004352 + +// commands: +#define READ_RTC 0 +#define SET_READ_SPEED 1 +#define DRIVE_STOP 2 +#define DRIVE_STANDBY 3 + +#define CdTrayOpen 0 +#define CdTrayClose 1 +#define CdTrayCheck 2 + +#endif // CDVDFS_COMMON_H diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/cdtypes.h b/backends/platform/ps2/iop/CoDyVDfs/iop/cdtypes.h new file mode 100644 index 0000000000..9f7a9762be --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/cdtypes.h @@ -0,0 +1,134 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __CDTYPES_H__ +#define __CDTYPES_H__ + +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +typedef signed int int32; +typedef signed short int16; +typedef signed char int8; + +typedef struct { + uint8 len_di; + uint8 attributeLength; + uint8 lba[4]; + uint16 parent; + char name[256]; // arbitrary number +} ISOPathTableRecord __attribute__ ((packed)); + +typedef struct { + uint8 year; // Number of years since 1900 + uint8 month; // Month of the year from 1 to 12 + uint8 day; // Day of the Month from 1 to 31 + uint8 hour; // Hour of the day from 0 to 23 + uint8 min; // Minute of the hour from 0 to 59 + uint8 sec; // second of the minute from 0 to 59 + uint8 gmtOff; // Offset from Greenwich Mean Time in number of 15 minute intervals from -48(West) to +52(East) + uint8 padding[10]; +} ISOTime __attribute__ ((packed)); + +typedef struct { + uint8 year; // Number of years since 1900 + uint8 month; // Month of the year from 1 to 12 + uint8 day; // Day of the Month from 1 to 31 + uint8 hour; // Hour of the day from 0 to 23 + uint8 min; // Minute of the hour from 0 to 59 + uint8 sec; // second of the minute from 0 to 59 + uint8 gmtOff; // Offset from Greenwich Mean Time in number of 15 minute intervals from -48(West) to +52(East) + //uint8 padding[10]; +} ISOFileTime __attribute__ ((packed)); + +typedef struct { + uint8 len_dr; + uint8 attributeLength; + uint8 lba[4]; + uint8 lba_BE[4]; + uint8 size[4]; + uint8 size_BE[4]; + ISOFileTime time; + uint8 flags; + uint8 fieldSize; + uint8 gapSize; + uint8 sequenceNumber[4]; + uint8 len_fi; + char name[256]; // arbitrary number +} ISODirectoryRecord __attribute__ ((packed)); + +typedef struct { + char volumeSetId[128]; + char publisherId[128]; + char preparerId[128]; + char applicationId[128]; + char copyrightId[37]; + char abstractId[37]; + char bibliographicId[37]; +} ISOIds __attribute__ ((packed)); + +typedef struct { + uint16 length; + uint32 tocLBA; + uint32 tocLBA_bigend; + uint32 tocSize; + uint32 tocSize_bigend; + uint8 dateStamp[8]; + uint8 reserved[6]; + uint8 reserved2; + uint8 reserved3; +} ISORoot __attribute__((packed)); // 0x22 + +typedef struct { + uint8 type; // 0x00 + char identifier[5]; // 0x01 + uint8 version; // 0x06 + uint8 reserved1; // 0x07 + char systemIdentifier[32]; // 0x08 + char volumeIdentifier[32]; // 0x28 + uint8 reserved2[8]; // 0x48 + uint32 volumeSpaceSize; // 0x50 + uint32 volumeSpaceSizeBE; // 0x54 + char reserved3[32]; // 0x58 + uint32 volumeSetSize; // 0x78 + uint32 volumeSequenceNumber; // 0x7C + uint32 logicalBlockSize; // 0x80 + uint32 pathTableSize; // 0x84 + uint32 pathTableSizeBE; // 0x88 + uint32 pathTablePos; // 0x8C + uint32 pathTable2Pos; // 0x90 + uint32 pathTablePosBE; // 0x94 + uint32 pathTable2PosBE; // 0x98 + ISORoot rootDir; // 0x9C + ISOIds ids; // 0xBE + ISOTime creation; // 0x32D + ISOTime modification; // 0x33E + ISOTime expiration; // 0x34F + ISOTime effective; // 0x360 + uint8 fileStructureVersion; // 0x371 + uint8 reserved4; // 0x372 + uint8 applicationUse[512]; // 0x373 + uint8 reserved5[653]; // 0x573 +} ISOPvd __attribute__ ((packed)); // 0x800 + +#endif // __CDTYPES_H__ + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.c b/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.c new file mode 100644 index 0000000000..627054e6fd --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.c @@ -0,0 +1,347 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <types.h> +#include <defs.h> +#include <irx.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <sysclib.h> +#include <sysmem.h> +#include <thbase.h> +#include <iomanX.h> + +#include <io_common.h> +#include <errno.h> + +#include "fiofs.h" +#include "codyvdfs.h" +#include "../common/codyvdirx.h" + +#define DBG_PRINTF printf + +char cachedDir[256]; +int cachedDirLba, cachedDirOfs, cachedDirSize; +static uint8 cacheBuf[2340]; + +int mediaType, fsRootLba, fsRootSize; + +int verifyDriveReady(void) { + int res; + u32 trayStat; + res = CdTrayReq(CdTrayCheck, &trayStat); + if ((mediaType == DISC_UNKNOWN) || (res == 0) || (trayStat == 1)) { + // media was exchanged + if (checkDiscReady(100) == 0) // wait up to 1 second + return initDisc(); + else { + mediaType = DISC_UNKNOWN; + return -1; // drive still not ready + } + } + if (mediaType == DISC_NONE) + return -1; + return 0; +} + +int cacheEnterDir(ISODirectoryRecord *dir) { + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + char *cacheName; + cachedDirLba = READ_ARRAY32(dir->lba); + cachedDirSize = READ_ARRAY32(dir->size); + cachedDirOfs = 0; + cacheName = cachedDir + strlen(cachedDir); + memcpy(cacheName, dir->name, dir->len_fi); + cacheName[dir->len_fi] = '/'; + cacheName[dir->len_fi + 1] = '\0'; + return cdReadSectors(cachedDirLba, 1, cacheBuf, &rmode); +} + +int initRootCache(void) { + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + ISODirectoryRecord *root = (ISODirectoryRecord*)cacheBuf; + + if (cdReadSectors(fsRootLba, 1, cacheBuf, &rmode) == 0) { + cachedDir[0] = '\0'; + fsRootSize = READ_ARRAY32(root->size); + cachedDirLba = fsRootLba; + cachedDirOfs = 0; + cachedDirSize = fsRootSize; + if (READ_ARRAY32(root->lba) == fsRootLba) + return 0; + } + DBG_PRINTF("Can't read root directory table in sector %d\n", fsRootLba); + mediaType = DISC_NONE; + return -1; +} + +ISODirectoryRecord *findEntryInCache(const char *name, int nameLen) { + int i; + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + ISODirectoryRecord *entry; + for (i = 0; i < NUM_SECTORS(cachedDirSize); i++) { + entry = (ISODirectoryRecord *)cacheBuf; + if (i != cachedDirOfs) { + if (cdReadSectors(cachedDirLba + i, 1, cacheBuf, &rmode) < 0) + return NULL; + cachedDirOfs = i; + } + + while (entry->len_dr && ((uint8*)entry < cacheBuf + SECTOR_SIZE)) { + if ((entry->len_fi > 2) && (entry->name[entry->len_fi - 2] == ';') && (entry->name[entry->len_fi - 1] == '1')) { + if ((nameLen == entry->len_fi - 2) && (strnicmp(name, entry->name, entry->len_fi - 2) == 0)) + return entry; + } else { + if ((nameLen == entry->len_fi) && (strnicmp(name, entry->name, entry->len_fi) == 0)) + return entry; + } + entry = (ISODirectoryRecord *)( (uint8*)entry + entry->len_dr ); + } + } + return NULL; +} + +ISODirectoryRecord *findPath(const char *path) { + ISODirectoryRecord *pathPos; + const char *tok; + + if (path[0] == '/') + path++; + + if (strnicmp(cachedDir, path, strlen(cachedDir)) == 0) + path += strlen(cachedDir); // requested path is somewhere in our cache + else + initRootCache(); // not cached, we start again at the cd root + + if (path[0] == '/') + path++; + + if (!path[0]) { // open root dir + if (cachedDirOfs) + initRootCache(); + return (ISODirectoryRecord *)cacheBuf; + } + + do { + tok = strchr(path, '/'); + if (tok) + pathPos = findEntryInCache(path, tok - path); + else + pathPos = findEntryInCache(path, strlen(path)); + + if (pathPos && tok && tok[1] && IS_DIR(pathPos)) + if (cacheEnterDir(pathPos) < 0) + return NULL; + + path = tok + 1; + } while (pathPos && tok && tok[1]); + return pathPos; +} + +int checkDiscReady(int retries) { + if (retries == -1) { + if (CdDiskReady(0) == 2) // block until drive ready, should always return 2 + return 0; + } else { + do { + if (CdDiskReady(1) == 2) + return 0; + DelayThread(10 * 1000); + } while (--retries >= 0); + } + return -1; +} + + +int initDisc(void) { + int type, sector, discType; + ISOPvd *pvd; + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + ISOPathTableRecord *rootRec; + + if (checkDiscReady(0) < 0) { + printf("disc not ready\n"); + mediaType = DISC_UNKNOWN; // retry later + return -1; + } + + do { // wait until drive detected disc type + type = CdGetDiskType(); + if (DISC_NOT_READY(type)) + DelayThread(10 * 1000); + } while (DISC_NOT_READY(type)); + + if (type == CdDiskIllegal) { + printf("Illegal disc type\n"); + mediaType = DISC_NONE; + return -1; + } + if (type == CdDiskNone) { + printf("Tray empty\n"); + mediaType = DISC_NONE; + return -1; + } + + discType = DISC_DVD; + switch (type) { + case CdDiskCDPS1: + case CdDiskCDDAPS1: + case CdDiskCDPS2: + case CdDiskCDDAPS2: + case CdDiskCDDA: + discType = DISC_MODE2; + rmode.datapattern = CdSect2340; + default: + break; + } + + for (sector = 16; sector < 32; sector++) { + printf("sec %d\n", sector); + if (cdReadSectors(sector, 1, cacheBuf, &rmode) == 0) { + if (discType == DISC_DVD) + pvd = (ISOPvd *)cacheBuf; + else { + switch (cacheBuf[3]) { + case 1: + discType = DISC_MODE1; + printf("Disc: Mode1\n"); + pvd = (ISOPvd*)(cacheBuf + 4); + break; + case 2: + discType = DISC_MODE2; + printf("Disc: Mode2\n"); + pvd = (ISOPvd*)(cacheBuf + 12); + break; + default: + DBG_PRINTF("Unknown Sector Type %02X\n", cacheBuf[3]); + return -1; + } + } + rmode.datapattern = CdSect2048; + if ((pvd->type == 1) && (memcmp(pvd->identifier, "CD001", 5) == 0)) { // found ISO9660 PVD + DBG_PRINTF("Found ISO9660 PVD in sector %d\n", sector); + + DBG_PRINTF("reading path table from sector %d\n", pvd->pathTablePos); + if (cdReadSectors(pvd->pathTablePos, 1, cacheBuf, &rmode) < 0) { + DBG_PRINTF("Can't read path table\n"); + return -1; + } + + rootRec = (ISOPathTableRecord *)cacheBuf; + if ((rootRec->len_di != 1) || (rootRec->name[0] != 0)) { + DBG_PRINTF("Root entry missing: %02X - %02X\n", rootRec->len_di, rootRec->name[0]); + return -1; + } + + fsRootLba = READ_ARRAY32(rootRec->lba); // this points to the root record + + mediaType = discType; + DBG_PRINTF("Root directory in sector %d\n", fsRootLba); + return initRootCache(); + } + } + } + mediaType = DISC_NONE; + // PVD not found + return -1; +} + +int cdReadSectors(int lba, int num, void *dest, CdRMode *rmode) { + int err; + if (CdRead(lba, num, dest, rmode) == 1) { + CdSync(0); + err = CdGetError(); + return (err > 0) ? -err : err; + } + return -0xFF; +} + +int cd_dummy(void) { + printf("cd_dummy called!\n"); + return -1; +} + +int cd_init(iop_device_t *dev) { + printf("FS init\n"); + memset(cachedDir, 0, 256); + cachedDirLba = cachedDirOfs = 0; + mediaType = DISC_UNKNOWN; + return 0; +} + +iop_device_ops_t FS_ops = { + (void *) cd_init, + (void *) cd_dummy, + (void *) cd_dummy, + (void *) cd_open, + (void *) cd_close, + (void *) cd_read, + (void *) cd_dummy, + (void *) cd_lseek, + (void *) cd_dummy, + (void *) cd_dummy, + (void *) cd_dummy, + (void *) cd_dummy, + (void *) cd_dopen, + (void *) cd_dclose, + (void *) cd_dread, + (void *) cd_dummy, + (void *) cd_dummy, +}; + +#define FS_NAME "cdfs" +#define FS_DESC "CD-ROM" + +iop_device_t fsdriver = { + FS_NAME, + IOP_DT_FS | IOP_DT_FSEXT, + 1, + FS_DESC, + &FS_ops +}; + +int _start(void) { + printf("CoDyVDfs v0.01\n"); + + CdInit(1); + DelDrv(FS_NAME); + AddDrv(&fsdriver); + + initRpc(); + initFio(); + return(0); +} + +int strnicmp(const char *s1, const char *s2, int n) { + if (n) { + do { + if (tolower(*s1) != tolower(*s2)) + return tolower(*s1) - tolower(*s2); + if (*s1++ == '\0') + break; + s2++; + } while (--n); + } + return 0; +} + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.h b/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.h new file mode 100644 index 0000000000..5e6295993c --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/codyvdfs.h @@ -0,0 +1,84 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __CoDyVDfs_H__ +#define __CoDyVDfs_H__ + +#include <cdvdman.h> +#include "cdtypes.h" + +typedef cd_read_mode_t CdRMode; + +// for reading misaligned ints +#define READ_ARRAY32(a) \ + (a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24)) + +#define SECTOR_SIZE 0x800 +#define SECTOR_MASK 0x7FF +#define NUM_SECTORS(a) ((a + 2047) >> 11) + +#define IS_DIR(a) ((a)->flags & 2) + +#define DISC_UNKNOWN 0xFE +#define DISC_NONE 0xFF +#define DISC_DVD 0 +#define DISC_MODE1 1 +#define DISC_MODE2 2 + +enum ReadModes { + CdSect2048 = 0, + CdSect2328, // 1 + CdSect2340 // 2 +}; + +enum { + CdDiskNone = 0x00, + CdDiskDetect, // 0x01 + CdDiskDetectCD, // 0x02 + CdDiskDetectDVD, // 0x03 + CdDiskDetectUnk = 0x05, + CdDiskCDPS1 = 0x10, + CdDiskCDDAPS1 = 0x11, + CdDiskCDPS2 = 0x12, + CdDiskCDDAPS2 = 0x13, + CdDiskDVDPS2 = 0x14, + CdDiskDVDV2 = 0xFC, + CdDiskCDDA = 0xFD, + CdDiskDVDV = 0xFE, + CdDiskIllegal = 0xFF +}; + +#define DISC_NOT_READY(type) ((type > CdDiskNone) && (type < CdDiskCDPS1) && (type != CdDiskDetectUnk)) + +int initRpc(void); + +int verifyDriveReady(void); +int cdReadSectors(int lba, int num, void *dest, CdRMode *rmode); +int initRootCache(void); +ISODirectoryRecord *findPath(const char *path); +int cacheEnterDir(ISODirectoryRecord *dir); +int initDisc(void); +int checkDiscReady(int retries); +int strnicmp(const char *s1, const char *s2, int n); + +#endif // __MYCDVDFS_H__ + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.c b/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.c new file mode 100644 index 0000000000..701ece1525 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.c @@ -0,0 +1,262 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "cdtypes.h" +#include "codyvdfs.h" +#include <iomanX.h> +#include <io_common.h> +#include <errno.h> +#include <sysmem.h> +#include <sysclib.h> +#include <sys/stat.h> + +#define MAX_DIO_HANDLES 8 +#define MAX_FIO_HANDLES 32 + +typedef struct { + int lba, size, lbaOfs; + uint32 curOfs; + uint8 *buf; +} DioHandle; + +typedef struct { + int lba, size; + int pos; + uint8 *buf; + int cachedLba; +} FioHandle; + +static DioHandle dioHandles[MAX_DIO_HANDLES]; +static FioHandle fioHandles[MAX_FIO_HANDLES]; + +int initFio(void) { + int i; + + for (i = 0; i < MAX_DIO_HANDLES; i++) + dioHandles[i].lba = 0; + for (i = 0; i < MAX_FIO_HANDLES; i++) + fioHandles[i].lba = 0; + return 0; +} + +int allocDioHandle(void) { + int i; + for (i = 0; i < MAX_DIO_HANDLES; i++) + if (!dioHandles[i].lba) + return i; + return -1; +} + +int allocFioHandle(void) { + int i; + for (i = 0; i < MAX_FIO_HANDLES; i++) + if (!fioHandles[i].lba) + return i; + return -1; +} + +int cd_open(iop_file_t *handle, const char *name, int mode) { + int fdSlot; + FioHandle *fd; + ISODirectoryRecord *rec; + + if (verifyDriveReady() < 0) + return -EIO; + + rec = findPath(name); + if (!rec || IS_DIR(rec)) + return -ENOENT; + + fdSlot = allocFioHandle(); + if (fdSlot < 0) + return -ENFILE; + + fd = fioHandles + fdSlot; + + fd->buf = AllocSysMemory(ALLOC_FIRST, 0x800, NULL); + if (!fd->buf) + return -ENOMEM; + + fd->lba = READ_ARRAY32(rec->lba); + fd->size = READ_ARRAY32(rec->size); + fd->pos = 0; + fd->cachedLba = 0; + + handle->privdata = (void*)fdSlot; + return 0; +} + +int cd_lseek(iop_file_t *handle, int ofs, int whence) { + FioHandle *fd = fioHandles + (int)handle->privdata; + int newOfs; + switch(whence) { + case SEEK_SET: + newOfs = ofs; + break; + case SEEK_CUR: + newOfs = fd->pos + ofs; + break; + case SEEK_END: + newOfs = fd->size + ofs; + break; + default: + newOfs = -1; + } + if ((newOfs >= 0) && (newOfs <= fd->size)) { + fd->pos = newOfs; + return newOfs; + } else + return -1; +} + +int cd_read(iop_file_t *handle, void *dest, int length) { + FioHandle *fd = fioHandles + (int)handle->privdata; + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + int readLba, readPos, bytesLeft; + uint8 *destPos = (uint8*)dest; + int doCopy; + int numLba; + readLba = fd->lba + (fd->pos >> 11); + readPos = fd->pos & 0x7FF; + + if (fd->pos + length > fd->size) + length = fd->size - fd->pos; + + if (length < 0) + return 0; + + bytesLeft = length; + while (bytesLeft > 0) { + if (readPos || (bytesLeft < 0x800) || (readLba == fd->cachedLba)) { + if (fd->cachedLba != readLba) { + if (cdReadSectors(readLba, 1, fd->buf, &rmode) == 0) + fd->cachedLba = readLba; + else + break; // read error + } + doCopy = 0x800 - readPos; + if (doCopy > bytesLeft) + doCopy = bytesLeft; + + memcpy(destPos, fd->buf + readPos, doCopy); + readPos += doCopy; + readLba += readPos >> 11; + readPos &= 0x7FF; + bytesLeft -= doCopy; + fd->pos += doCopy; + destPos += doCopy; + } else { + numLba = bytesLeft >> 11; + if (cdReadSectors(readLba, numLba, destPos, &rmode) != 0) + break; + readLba += numLba; + fd->pos += numLba << 11; + destPos += numLba << 11; + bytesLeft &= 0x7FF; + } + } + return destPos - (uint8*)dest; +} + +int cd_close(iop_file_t *handle) { + FioHandle *hd = fioHandles + (int)handle->privdata; + FreeSysMemory(hd->buf); + hd->lba = hd->pos = hd->size = 0; + hd->buf = 0; + return 0; +} + +int cd_dopen(iop_file_t *handle, const char *path) { + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + int fdSlot; + ISODirectoryRecord *rec; + + if (verifyDriveReady() < 0) + return -EIO; + + rec = findPath(path); + if (!rec || !IS_DIR(rec)) + return -ENOENT; + + fdSlot = allocDioHandle(); + + if (fdSlot < 0) + return -ENFILE; + + dioHandles[fdSlot].buf = AllocSysMemory(ALLOC_FIRST, 0x800, NULL); + if (!dioHandles[fdSlot].buf) + return -ENOMEM; + + dioHandles[fdSlot].lba = READ_ARRAY32(rec->lba); + dioHandles[fdSlot].size = READ_ARRAY32(rec->size); + if (cdReadSectors(dioHandles[fdSlot].lba, 1, dioHandles[fdSlot].buf, &rmode) != 0) { + dioHandles[fdSlot].lba = dioHandles[fdSlot].size = 0; + FreeSysMemory(dioHandles[fdSlot].buf); + dioHandles[fdSlot].buf = NULL; + return -EIO; + } + dioHandles[fdSlot].curOfs = 0; + dioHandles[fdSlot].lbaOfs = 0; + handle->privdata = (void*)fdSlot; + return fdSlot; +} + +int cd_dread(iop_file_t *handle, iox_dirent_t *buf) { + CdRMode rmode = { 16, 0, CdSect2048, 0 }; + ISODirectoryRecord *rec; + DioHandle *hd = dioHandles + (int)handle->privdata; + int i; + for (i = hd->lbaOfs; i < NUM_SECTORS(hd->size); i++) { + if (i != hd->lbaOfs) { + cdReadSectors(hd->lba + i, 1, hd->buf, &rmode); + hd->lbaOfs = i; + hd->curOfs = 0; + } + while ((hd->curOfs < SECTOR_SIZE) && ((ISODirectoryRecord *)(hd->buf + hd->curOfs))->len_dr) { + rec = (ISODirectoryRecord *)(hd->buf + hd->curOfs); + hd->curOfs += rec->len_dr; + if ((rec->len_fi != 1) || ((rec->name[0] != 0) && (rec->name[0] != 1))) { // skip '.' / '..' + memcpy(buf->name, rec->name, rec->len_fi); + if ((buf->name[rec->len_fi - 2] == ';') && (buf->name[rec->len_fi - 1] == '1')) + buf->name[rec->len_fi - 2] = '\0'; + else + buf->name[rec->len_fi] = '\0'; + buf->stat.mode = FIO_S_IRUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IXOTH; + buf->stat.mode |= IS_DIR(rec) ? FIO_S_IFDIR : FIO_S_IFREG; + buf->stat.attr = 0; + buf->stat.size = READ_ARRAY32(rec->size); + buf->stat.hisize = 0; + return 1; + } + } + } + return 0; +} + +int cd_dclose(iop_file_t *handle) { + DioHandle *hd; + hd = dioHandles + (int)handle->privdata; + FreeSysMemory(hd->buf); + hd->size = hd->lba = 0; + return 0; +} + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.h b/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.h new file mode 100644 index 0000000000..21d7dff218 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/fiofs.h @@ -0,0 +1,37 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __FIOFS_H__ +#define __FIOFS_H__ + +int initFio(void); + +int cd_open(iop_file_t *handle, const char *name, int mode); +int cd_lseek(iop_file_t *handle, int ofs, int whence); +int cd_read(iop_file_t *handle, void *dest, int length); +int cd_close(iop_file_t *handle); +int cd_dopen(iop_file_t *handle, const char *path); +int cd_dread(iop_file_t *handle, fio_dirent_t *buf); +int cd_dclose(iop_file_t *handle); + +#endif // __FIOFS_H__ + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/imports.lst b/backends/platform/ps2/iop/CoDyVDfs/iop/imports.lst new file mode 100644 index 0000000000..d3ed3b0442 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/imports.lst @@ -0,0 +1,65 @@ + +cdvdman_IMPORTS_start +I_sceCdInit +I_sceCdStandby +I_sceCdRead +I_sceCdSeek +I_sceCdGetError +I_sceCdSync +I_sceCdGetDiskType +I_sceCdDiskReady +I_sceCdTrayReq +I_sceCdStop +I_sceCdReadClock +cdvdman_IMPORTS_end + +intrman_IMPORTS_start +I_CpuSuspendIntr +I_CpuResumeIntr +intrman_IMPORTS_end + +iomanX_IMPORTS_start +I_AddDrv +I_DelDrv +iomanX_IMPORTS_end + +sifcmd_IMPORTS_start +I_sceSifInitRpc +I_sceSifSetRpcQueue +I_sceSifRegisterRpc +I_sceSifRpcLoop +sifcmd_IMPORTS_end + +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +sysclib_IMPORTS_start +I_memcmp +I_memcpy +I_memset +I_strlen +I_strncmp +I_strtoul +I_strcpy +I_strcat +I_strchr +I_strncpy +I_strtok +I_strrchr +I_tolower +sysclib_IMPORTS_end + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +sysmem_IMPORTS_end + +thbase_IMPORTS_start +I_CreateThread +I_StartThread +I_GetThreadId +I_DelayThread +thbase_IMPORTS_end + + diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/irx_imports.h b/backends/platform/ps2/iop/CoDyVDfs/iop/irx_imports.h new file mode 100644 index 0000000000..1f974cf834 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/irx_imports.h @@ -0,0 +1,30 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org> +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include "irx.h" + +/* Please keep these in alphabetical order! */ +#include "cdvdman.h" +#include "intrman.h" +#include "iomanX.h" +#include "loadcore.h" +#include "sifcmd.h" +#include "stdio.h" +#include "sysclib.h" +#include "sysmem.h" +#include "thbase.h" + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/backends/platform/ps2/iop/CoDyVDfs/iop/rpcfs.c b/backends/platform/ps2/iop/CoDyVDfs/iop/rpcfs.c new file mode 100644 index 0000000000..16f70e9ed4 --- /dev/null +++ b/backends/platform/ps2/iop/CoDyVDfs/iop/rpcfs.c @@ -0,0 +1,115 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <sifman.h> +#include <sifrpc.h> +#include <thbase.h> +#include <stdio.h> +#include "codyvdfs.h" +#include "../common/codyvdirx.h" + +struct t_SifRpcDataQueue qd; +struct t_SifRpcServerData sd0; +static uint8 rpcBuffer[64]; + +void *rpcServer(int func, void *data, int size); +void rpcThread(void *param); + +int initRpc(void) { + iop_thread_t thread; + int tid; + + thread.attr = TH_C; + thread.thread = rpcThread; + thread.priority = 40; + thread.stacksize = 0x1000; + thread.attr = 0; + + tid = CreateThread(&thread); + if (tid >= 0) + StartThread(tid, 0); + else { + printf("Unable to start RPC Thread!\n"); + return -1; + } + return 0; +} + +void rpcThread(void *param) { + SifInitRpc(0); + SifSetRpcQueue(&qd, GetThreadId()); + SifRegisterRpc(&sd0, CDVDFS_IRX_ID, rpcServer, (void *)rpcBuffer, 0, 0, &qd); + SifRpcLoop(&qd); +} + +void *rpcReadClock(void *data) { + CdReadClock((cd_clock_t *)data); + return data; +} + +void *driveStop(void *data) { + if (CdStop() == 1) { + if (CdSync(0) == 0) { + *(int*)data = CdGetError(); + } else + *(int*)data = -0x100; + } else + *(int*)data = -0x101; + return data; +} + +void *driveStandby(void *data) { + int type; + if (CdStandby() == 1) { + if (CdSync(0) == 0) { + *(int*)data = CdGetError(); + } else + *(int*)data = -0x100; + } else + *(int*)data = -0x101; + + do { // wait until drive detected disc type + type = CdGetDiskType(); + if (DISC_NOT_READY(type)) + DelayThread(10 * 1000); + } while (DISC_NOT_READY(type)); + printf("Standby: Disc type: %02X\n", type); + + return data; +} + +void *rpcServer(int func, void *data, int size) { + switch (func) { + case READ_RTC: + return rpcReadClock(data); + case DRIVE_STOP: + return driveStop(data); + case DRIVE_STANDBY: + return driveStandby(data); + default: + printf("Unknown RPC command %d\n", func); + return NULL; + } + return NULL; +} + + diff --git a/backends/platform/ps2/irxboot.cpp b/backends/platform/ps2/irxboot.cpp new file mode 100644 index 0000000000..fc844fc319 --- /dev/null +++ b/backends/platform/ps2/irxboot.cpp @@ -0,0 +1,215 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <kernel.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sifrpc.h> +#include <loadfile.h> +#include <malloc.h> +#include "backends/ps2/irxboot.h" + +extern void sioprintf(const char *zFormat, ...); + +static const char hddArg[] = "-o" "\0" "4" "\0" "-n" "\0" "20"; +static const char pfsArg[] = "-m" "\0" "2" "\0" "-o" "\0" "16" "\0" "-n" "\0" "40" /*"\0" "-debug"*/; + +IrxFile irxFiles[] = { + { "SIO2MAN", BIOS, NOTHING, NULL, 0 }, + { "MCMAN", BIOS, NOTHING, NULL, 0 }, + { "MCSERV", BIOS, NOTHING, NULL, 0 }, + { "PADMAN", BIOS, NOTHING, NULL, 0 }, + { "LIBSD", BIOS, NOTHING, NULL, 0 }, + + { "IOMANX.IRX", SYSTEM | NOT_HOST, NOTHING, NULL, 0 }, // already loaded by ps2link + { "FILEXIO.IRX", SYSTEM, NOTHING, NULL, 0 }, + { "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 }, + { "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 }, + + { "USBD.IRX", USB | OPTIONAL | DEPENDANCY, USB_DRIVER, NULL, 0 }, + { "PS2MOUSE.IRX", USB | OPTIONAL, MOUSE_DRIVER, NULL, 0 }, + { "RPCKBD.IRX", USB | OPTIONAL, KBD_DRIVER, NULL, 0 }, + { "USB_MASS.IRX", USB | OPTIONAL, MASS_DRIVER, NULL, 0 }, + + { "PS2DEV9.IRX", HDD | OPTIONAL | DEPENDANCY, HDD_DRIVER, NULL, 0 }, + { "PS2ATAD.IRX", HDD | OPTIONAL | DEPENDANCY, HDD_DRIVER, NULL, 0 }, + { "PS2HDD.IRX", HDD | OPTIONAL | DEPENDANCY, HDD_DRIVER, hddArg, sizeof(hddArg) }, + { "PS2FS.IRX", HDD | OPTIONAL | DEPENDANCY, HDD_DRIVER, pfsArg, sizeof(pfsArg) }, + { "POWEROFF.IRX", HDD | OPTIONAL | DEPENDANCY, HDD_DRIVER, NULL, 0 } +}; + +static const int numIrxFiles = sizeof(irxFiles) / sizeof(irxFiles[0]); + +BootDevice detectBootPath(const char *elfPath, char *bootPath) { + + BootDevice device; + + if (strncasecmp(elfPath, "cdrom0:", 7) == 0) + device = CDROM; + else if (strncasecmp(elfPath, "host", 4) == 0) + device = HOST; + else + device = OTHER; + + sioprintf("elf path: %s, device %d", elfPath, device); + + strcpy(bootPath, elfPath); + + char *pathPos = bootPath; + char seperator; + + if (device == CDROM) { + // CDVD uses '\' as seperator + while (*pathPos) { + if (*pathPos == '/') + *pathPos = '\\'; + pathPos++; + } + seperator = '\\'; + } else { + // all the other devices use '/' + while (*pathPos) { + if (*pathPos == '\\') + *pathPos = '/'; + pathPos++; + } + seperator = '/'; + } + pathPos = strrchr(bootPath, seperator); + if (!pathPos) + pathPos = strchr(bootPath, ':'); + + if (pathPos) { + if ((pathPos[0] == ':') && (device == CDROM)) { + pathPos[1] = '\\'; + pathPos[2] = '\0'; + } else + pathPos[1] = '\0'; + sioprintf("done. IRX path: \"%s\"", bootPath); + } else { + sioprintf("path not recognized, default to host."); + strcpy(bootPath, "host:"); + device = UNKNOWN; + } + return device; +} + +int loadIrxModules(int device, const char *irxPath, IrxReference **modules) { + + IrxReference *resModules = (IrxReference *)malloc(numIrxFiles * sizeof(IrxReference)); + IrxReference *curModule = resModules; + + for (int i = 0; i < numIrxFiles; i++) { + curModule->fileRef = irxFiles + i; + if ((device == HOST) && (irxFiles[i].flags & NOT_HOST)) + continue; + + if ((irxFiles[i].flags & TYPEMASK) == BIOS) { + curModule->loc = IRX_FILE; + curModule->path = (char *)malloc(32); + sprintf(curModule->path, "rom0:%s", irxFiles[i].name); + curModule->buffer = NULL; + curModule->size = 0; + curModule->argSize = 0; + curModule->args = NULL; + curModule->errorCode = 0; + } else { + curModule->loc = IRX_BUFFER; + curModule->path = (char *)malloc(256); + + sprintf(curModule->path, "%s%s%s", irxPath, irxFiles[i].name, (device == CDROM) ? ";1" : ""); + int fd = fioOpen(curModule->path, O_RDONLY); + if (fd < 0) { + // IRX not found + sioprintf("Can't open %s: %d", curModule->path, fd); + // we keep the error code of the path where we originally expected the file + curModule->errorCode = fd; + + // try cdrom root directory + sprintf(curModule->path, "cdrom0:\\%s;1", irxFiles[i].name); + fd = fioOpen(curModule->path, O_RDONLY); + if (fd < 0) { + // still not found, try host: + sioprintf("Can't open %s: %d", curModule->path, fd); + sprintf(curModule->path, "host:%s", irxFiles[i].name); + fd = fioOpen(curModule->path, O_RDONLY); + if (fd < 0) { + // we simply can't find it. + sioprintf("Can't open %s: %d", curModule->path, fd); + // restore the path where we originally expected the file, for error message (later, after boot up) + sprintf(curModule->path, "%s%s%s", irxPath, irxFiles[i].name, (device == CDROM) ? ";1" : ""); + } + } + } + + if (fd >= 0) { + curModule->size = fioLseek(fd, 0, SEEK_END); + fioLseek(fd, 0, SEEK_SET); + curModule->buffer = (uint8 *)memalign(64, (curModule->size + 63) & ~63); + fioRead(fd, curModule->buffer, curModule->size); + + curModule->argSize = irxFiles[i].argSize; + curModule->args = irxFiles[i].args; + curModule->errorCode = 0; + fioClose(fd); + } else { + if (irxFiles[i].flags & DEPENDANCY) { + // other modules depend on this one. + // kill the modules we already loaded, if they depend on the one that failed. + IrxReference *pos = resModules; + while (pos < curModule) { + if ((pos->fileRef->flags & TYPEMASK) == (irxFiles[i].flags & TYPEMASK)) { + if (pos->path) + free(pos->path); + if (pos->buffer) + free(pos->buffer); + + IrxReference *copyPos = pos; + while (copyPos < curModule) { + copyPos[0] = copyPos[1]; + copyPos++; + } + curModule--; + } else + pos++; + } + // and skip any remaining modules that depend on the missing one, too. + while ((i < numIrxFiles - 1) && ((irxFiles[i + 1].flags & TYPEMASK) == (curModule->fileRef->flags & TYPEMASK))) + i++; + // the module that actually failed (curModule) is kept in the array for displaying an error message + } + curModule->size = 0; + curModule->buffer = NULL; + curModule->argSize = 0; + curModule->args = NULL; + } + } + curModule++; + } + *modules = resModules; + sioprintf("List of %d modules:", curModule - resModules); + for (int i = 0; i < curModule - resModules; i++) + sioprintf("%s", resModules[i].path); + return curModule - resModules; +} + diff --git a/backends/platform/ps2/irxboot.h b/backends/platform/ps2/irxboot.h new file mode 100644 index 0000000000..c41a4ac311 --- /dev/null +++ b/backends/platform/ps2/irxboot.h @@ -0,0 +1,84 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __IRXBOOT_H__ +#define __IRXBOOT_H__ + +#include "common/scummsys.h" + +enum IrxFlags { + BIOS = 0, + SYSTEM = 1, + USB = 2, + HDD = 3, + TYPEMASK = 3, + + OPTIONAL = 4, + DEPENDANCY = 8, + NOT_HOST = 16 +}; + +enum IrxPurpose { + NOTHING, + HDD_DRIVER, + USB_DRIVER, + MOUSE_DRIVER, + KBD_DRIVER, + MASS_DRIVER +}; + +enum IrxLocation { + IRX_BUFFER, + IRX_FILE +}; + +enum BootDevice { + HOST = 0, + CDROM, + OTHER, + UNKNOWN +}; + +struct IrxFile { + const char *name; + int flags; + IrxPurpose purpose; + const char *args; + int argSize; +}; + +struct IrxReference { + IrxFile *fileRef; + IrxLocation loc; + char *path; + void *buffer; + uint32 size; + uint32 argSize; + const char *args; + int errorCode; +}; + +BootDevice detectBootPath(const char *elfPath, char *bootPath); +int loadIrxModules(int device, const char *irxPath, IrxReference **modules); + +#endif // __IRXBOOT_H__ + diff --git a/backends/platform/ps2/ps2input.cpp b/backends/platform/ps2/ps2input.cpp new file mode 100644 index 0000000000..b3835ef648 --- /dev/null +++ b/backends/platform/ps2/ps2input.cpp @@ -0,0 +1,547 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <kernel.h> +#include <malloc.h> +#include <assert.h> +#include <libmouse.h> +#include "backends/ps2/rpckbd.h" +#include "backends/ps2/ps2input.h" +#include "backends/ps2/ps2pad.h" +#include "backends/ps2/systemps2.h" +#include "backends/ps2/sdlkeys.h" +#include "common/system.h" + +Ps2Input::Ps2Input(OSystem_PS2 *system, bool mouseLoaded, bool kbdLoaded) { + _system = system; + _mouseLoaded = mouseLoaded; + _kbdLoaded = kbdLoaded; + _pad = new Ps2Pad(system); + _lastPadCheck = 0; + _posX = _posY = _mButtons = _padLastButtons = 0; + _padAccel = 0; + _minx = _miny = 0; + _maxy = 239; + _maxx = 319; + _keyFlags = 0; + if (_mouseLoaded) { + if (PS2MouseInit() >= 0) { + PS2MouseSetReadMode(PS2MOUSE_READMODE_ABS); + printf("PS2Mouse initialized\n"); + } else { // shouldn't happen if the drivers were correctly loaded + printf("unable to initialize PS2Mouse!\n"); + _mouseLoaded = false; + } + } + if (_kbdLoaded) { + if (PS2KbdInit() >= 0) { + PS2KbdSetReadmode(PS2KBD_READMODE_RAW); + printf("PS2Kbd initialized\n"); + } else { + printf("unable to initialize PS2Kbd!\n"); + _kbdLoaded = false; + } + } +} + +Ps2Input::~Ps2Input(void) { +} + +void Ps2Input::newRange(uint16 minx, uint16 miny, uint16 maxx, uint16 maxy) { + _minx = minx; + _miny = miny; + _maxx = maxx; + _maxy = maxy; + if (_mouseLoaded) + PS2MouseSetBoundary(minx, maxx, miny, maxy); + warpTo(_posX, _posY); +} + +void Ps2Input::warpTo(uint16 x, uint16 y) { + if ((x >= _minx) && (x <= _maxx) && (y >= _miny) && (y <= _maxy)) { + _posX = x; + _posY = y; + } else { + _posX = (x < _minx) ? (_minx) : ((x > _maxx) ? (_maxx) : (x)); + _posY = (y < _miny) ? (_miny) : ((y > _maxy) ? (_maxy) : (y)); + } + if (_mouseLoaded) + PS2MouseSetPosition(_posX, _posY); +} + +#define JOY_THRESHOLD 30 +#define PAD_CHECK_TIME 20 + +int Ps2Input::mapKey(int key, int mod) { // copied from sdl backend + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + 315; + } else if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (key >= 'a' && key <= 'z' && mod & OSystem::KBD_SHIFT) { + return key & ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +bool Ps2Input::pollEvent(OSystem::Event *event) { + bool checkPadMouse, checkPadKbd; + checkPadMouse = checkPadKbd = _pad->padAlive(); + + if (_mouseLoaded && (PS2MouseEnum() > 0)) { // usb mouse connected + mouse_data mData; + PS2MouseRead(&mData); + if ((_posX != mData.x) || (_posY != mData.y)) { + event->mouse.x = _posX = mData.x; + event->mouse.y = _posY = mData.y; + event->type = OSystem::EVENT_MOUSEMOVE; + return true; + } + if (mData.buttons != _mButtons) { + uint16 change = _mButtons ^ mData.buttons; + _mButtons = mData.buttons; + if (change & (PS2MOUSE_BTN1 | PS2MOUSE_BTN2)) { + if (change & PS2MOUSE_BTN1) + event->type = (_mButtons & PS2MOUSE_BTN1) ? OSystem::EVENT_LBUTTONDOWN : OSystem::EVENT_LBUTTONUP; + else + event->type = (_mButtons & PS2MOUSE_BTN2) ? OSystem::EVENT_RBUTTONDOWN : OSystem::EVENT_RBUTTONUP; + event->mouse.x = _posX; + event->mouse.y = _posY; + return true; + } + } + checkPadMouse = false; + } + if (_kbdLoaded) { // there's no way to tell if there's actually a keyboard connected + PS2KbdRawKey key; + if (PS2KbdReadRaw(&key) == 1) { + if (_usbToSdlk[key.key]) { + if ((_usbToSdlk[key.key] == SDLK_LSHIFT) || (_usbToSdlk[key.key] == SDLK_RSHIFT)) { + if (key.state & 1) + _keyFlags |= OSystem::KBD_SHIFT; + else + _keyFlags &= ~OSystem::KBD_SHIFT; + } else if ((_usbToSdlk[key.key] == SDLK_LCTRL) || (_usbToSdlk[key.key] == SDLK_RCTRL)) { + if (key.state & 1) + _keyFlags |= OSystem::KBD_CTRL; + else + _keyFlags &= ~OSystem::KBD_CTRL; + } else if ((_usbToSdlk[key.key] == SDLK_LALT) || (_usbToSdlk[key.key] == SDLK_RALT)) { + if (key.state & 1) + _keyFlags |= OSystem::KBD_ALT; + else + _keyFlags &= ~OSystem::KBD_ALT; + } + if (key.state & 1) // down + event->type = OSystem::EVENT_KEYDOWN; + else + event->type = OSystem::EVENT_KEYUP; + event->kbd.flags = 0; + event->kbd.keycode = _usbToSdlk[key.key]; + event->kbd.ascii = mapKey(_usbToSdlk[key.key], _keyFlags); + return true; + } else + printf("unknown keycode %02X - %02X\n", key.state, key.key); + } + } + if (checkPadMouse || checkPadKbd) { + // no usb mouse, simulate it using the pad + uint16 buttons; + int16 joyh, joyv; + _pad->readPad(&buttons, &joyh, &joyv); + uint16 btnChange = buttons ^ _padLastButtons; + + if (checkPadMouse) { + if (btnChange & (PAD_CROSS | PAD_CIRCLE)) { + if (btnChange & PAD_CROSS) + event->type = (buttons & PAD_CROSS) ? OSystem::EVENT_LBUTTONDOWN : OSystem::EVENT_LBUTTONUP; + else + event->type = (buttons & PAD_CIRCLE) ? OSystem::EVENT_RBUTTONDOWN : OSystem::EVENT_RBUTTONUP; + event->mouse.x = _posX; + event->mouse.y = _posY; + _padLastButtons = buttons; + return true; + } + uint32 time = _system->getMillis(); + if (time - _lastPadCheck > PAD_CHECK_TIME) { + _lastPadCheck = time; + int16 newX = _posX; + int16 newY = _posY; + if ((ABS(joyh) > JOY_THRESHOLD) || (ABS(joyv) > JOY_THRESHOLD)) { + newX += joyh / 20; + newY += joyv / 20; + } else if (buttons & PAD_DIR_MASK) { + if (_padLastButtons & PAD_DIR_MASK) { + if (_padAccel < 16) + _padAccel++; + } else + _padAccel = 0; + _padLastButtons = buttons; + if (buttons & PAD_LEFT) + newX -= _padAccel >> 2; + if (buttons & PAD_RIGHT) + newX += _padAccel >> 2; + if (buttons & PAD_UP) + newY -= _padAccel >> 2; + if (buttons & PAD_DOWN) + newY += _padAccel >> 2; + } + newX = ((newX < (int16)_minx) ? (_minx) : ((newX > (int16)_maxx) ? (_maxx) : ((int16)newX))); + newY = ((newY < (int16)_miny) ? (_miny) : ((newY > (int16)_maxy) ? (_maxy) : ((int16)newY))); + if ((_posX != newX) || (_posY != newY)) { + event->type = OSystem::EVENT_MOUSEMOVE; + event->mouse.x = _posX = newX; + event->mouse.y = _posY = newY; + return true; + } + } + } + if (checkPadKbd) { + if (getKeyEvent(event, btnChange, (btnChange & buttons) != 0)) { + _padLastButtons = buttons; + return true; + } + } + } + return false; +} + +bool Ps2Input::getKeyEvent(OSystem::Event *event, uint16 buttonCode, bool down) { + // for simulating key presses with the pad + if (buttonCode) { + uint8 entry = 0; + while (!(buttonCode & 1)) { + entry++; + buttonCode >>= 1; + } + if (_padCodes[entry]) { + event->type = (down) ? OSystem::EVENT_KEYDOWN : OSystem::EVENT_KEYUP; + event->kbd.keycode = _padCodes[entry]; + event->kbd.flags = _padFlags[entry]; + event->kbd.ascii = mapKey(_padCodes[entry], _padFlags[entry]); + return true; + } + } + return false; +} + +const int Ps2Input::_usbToSdlk[0x100] = { + /* 00 */ 0, + /* 01 */ 0, + /* 02 */ 0, + /* 03 */ 0, + /* 04 */ SDLK_a, + /* 05 */ SDLK_b, + /* 06 */ SDLK_c, + /* 07 */ SDLK_d, + /* 08 */ SDLK_e, + /* 09 */ SDLK_f, + /* 0A */ SDLK_g, + /* 0B */ SDLK_h, + /* 0C */ SDLK_i, + /* 0D */ SDLK_j, + /* 0E */ SDLK_k, + /* 0F */ SDLK_l, + /* 10 */ SDLK_m, + /* 11 */ SDLK_n, + /* 12 */ SDLK_o, + /* 13 */ SDLK_p, + /* 14 */ SDLK_q, + /* 15 */ SDLK_r, + /* 16 */ SDLK_s, + /* 17 */ SDLK_t, + /* 18 */ SDLK_u, + /* 19 */ SDLK_v, + /* 1A */ SDLK_w, + /* 1B */ SDLK_x, + /* 1C */ SDLK_y, + /* 1D */ SDLK_z, + /* 1E */ SDLK_1, + /* 1F */ SDLK_2, + /* 20 */ SDLK_3, + /* 21 */ SDLK_4, + /* 22 */ SDLK_5, + /* 23 */ SDLK_6, + /* 24 */ SDLK_7, + /* 25 */ SDLK_8, + /* 26 */ SDLK_9, + /* 27 */ SDLK_0, + /* 28 */ SDLK_RETURN, + /* 29 */ SDLK_ESCAPE, + /* 2A */ SDLK_BACKSPACE, + /* 2B */ SDLK_TAB, + /* 2C */ SDLK_SPACE, + /* 2D */ SDLK_MINUS, + /* 2E */ SDLK_EQUALS, + /* 2F */ SDLK_LEFTBRACKET, + /* 30 */ SDLK_RIGHTBRACKET, + /* 31 */ SDLK_BACKSLASH, + /* 32 */ SDLK_HASH, + /* 33 */ SDLK_SEMICOLON, + /* 34 */ SDLK_QUOTE, + /* 35 */ SDLK_BACKQUOTE, + /* 36 */ SDLK_COMMA, + /* 37 */ SDLK_PERIOD, + /* 38 */ SDLK_SLASH, + /* 39 */ SDLK_CAPSLOCK, + /* 3A */ SDLK_F1, + /* 3B */ SDLK_F2, + /* 3C */ SDLK_F3, + /* 3D */ SDLK_F4, + /* 3E */ SDLK_F5, + /* 3F */ SDLK_F6, + /* 40 */ SDLK_F7, + /* 41 */ SDLK_F8, + /* 42 */ SDLK_F9, + /* 43 */ SDLK_F10, + /* 44 */ SDLK_F11, + /* 45 */ SDLK_F12, + /* 46 */ SDLK_PRINT, + /* 47 */ SDLK_SCROLLOCK, + /* 48 */ SDLK_PAUSE, + /* 49 */ SDLK_INSERT, + /* 4A */ SDLK_HOME, + /* 4B */ SDLK_PAGEUP, + /* 4C */ SDLK_DELETE, + /* 4D */ SDLK_END, + /* 4E */ SDLK_PAGEDOWN, + /* 4F */ SDLK_RIGHT, + /* 50 */ SDLK_LEFT, + /* 51 */ SDLK_DOWN, + /* 52 */ SDLK_UP, + /* 53 */ SDLK_NUMLOCK, + /* 54 */ SDLK_KP_DIVIDE, + /* 55 */ SDLK_KP_MULTIPLY, + /* 56 */ SDLK_KP_MINUS, + /* 57 */ SDLK_KP_PLUS, + /* 58 */ SDLK_KP_ENTER, + /* 59 */ SDLK_KP1, + /* 5A */ SDLK_KP2, + /* 5B */ SDLK_KP3, + /* 5C */ SDLK_KP4, + /* 5D */ SDLK_KP5, + /* 5E */ SDLK_KP6, + /* 5F */ SDLK_KP7, + /* 60 */ SDLK_KP8, + /* 61 */ SDLK_KP9, + /* 62 */ SDLK_KP0, + /* 63 */ SDLK_KP_PERIOD, + /* 64 */ 0, + /* 65 */ 0, + /* 66 */ 0, + /* 67 */ SDLK_KP_EQUALS, + /* 68 */ 0, + /* 69 */ 0, + /* 6A */ 0, + /* 6B */ 0, + /* 6C */ 0, + /* 6D */ 0, + /* 6E */ 0, + /* 6F */ 0, + /* 70 */ 0, + /* 71 */ 0, + /* 72 */ 0, + /* 73 */ 0, + /* 74 */ 0, + /* 75 */ 0, + /* 76 */ 0, + /* 77 */ 0, + /* 78 */ 0, + /* 79 */ 0, + /* 7A */ 0, + /* 7B */ 0, + /* 7C */ 0, + /* 7D */ 0, + /* 7E */ 0, + /* 7F */ 0, + /* 80 */ 0, + /* 81 */ 0, + /* 82 */ 0, + /* 83 */ 0, + /* 84 */ 0, + /* 85 */ 0, + /* 86 */ 0, + /* 87 */ 0, + /* 88 */ 0, + /* 89 */ 0, + /* 8A */ 0, + /* 8B */ 0, + /* 8C */ 0, + /* 8D */ 0, + /* 8E */ 0, + /* 8F */ 0, + /* 90 */ 0, + /* 91 */ 0, + /* 92 */ 0, + /* 93 */ 0, + /* 94 */ 0, + /* 95 */ 0, + /* 96 */ 0, + /* 97 */ 0, + /* 98 */ 0, + /* 99 */ 0, + /* 9A */ 0, + /* 9B */ 0, + /* 9C */ 0, + /* 9D */ 0, + /* 9E */ 0, + /* 9F */ 0, + /* A0 */ 0, + /* A1 */ 0, + /* A2 */ 0, + /* A3 */ 0, + /* A4 */ 0, + /* A5 */ 0, + /* A6 */ 0, + /* A7 */ 0, + /* A8 */ 0, + /* A9 */ 0, + /* AA */ 0, + /* AB */ 0, + /* AC */ 0, + /* AD */ 0, + /* AE */ 0, + /* AF */ 0, + /* B0 */ 0, + /* B1 */ 0, + /* B2 */ 0, + /* B3 */ 0, + /* B4 */ 0, + /* B5 */ 0, + /* B6 */ 0, + /* B7 */ 0, + /* B8 */ 0, + /* B9 */ 0, + /* BA */ 0, + /* BB */ 0, + /* BC */ 0, + /* BD */ 0, + /* BE */ 0, + /* BF */ 0, + /* C0 */ 0, + /* C1 */ 0, + /* C2 */ 0, + /* C3 */ 0, + /* C4 */ 0, + /* C5 */ 0, + /* C6 */ 0, + /* C7 */ 0, + /* C8 */ 0, + /* C9 */ 0, + /* CA */ 0, + /* CB */ 0, + /* CC */ 0, + /* CD */ 0, + /* CE */ 0, + /* CF */ 0, + /* D0 */ 0, + /* D1 */ 0, + /* D2 */ 0, + /* D3 */ 0, + /* D4 */ 0, + /* D5 */ 0, + /* D6 */ 0, + /* D7 */ 0, + /* D8 */ 0, + /* D9 */ 0, + /* DA */ 0, + /* DB */ 0, + /* DC */ 0, + /* DD */ 0, + /* DE */ 0, + /* DF */ 0, + /* E0 */ SDLK_LCTRL, + /* E1 */ SDLK_LSHIFT, + /* E2 */ SDLK_LALT, + /* E3 */ 0, + /* E4 */ SDLK_RCTRL, + /* E5 */ SDLK_RSHIFT, + /* E6 */ SDLK_RALT, + /* E7 */ 0, + /* E8 */ 0, + /* E9 */ 0, + /* EA */ 0, + /* EB */ 0, + /* EC */ 0, + /* ED */ 0, + /* EE */ 0, + /* EF */ 0, + /* F0 */ 0, + /* F1 */ 0, + /* F2 */ 0, + /* F3 */ 0, + /* F4 */ 0, + /* F5 */ 0, + /* F6 */ 0, + /* F7 */ 0, + /* F8 */ 0, + /* F9 */ 0, + /* FA */ 0, + /* FB */ 0, + /* FC */ 0, + /* FD */ 0, + /* FE */ 0, + /* FF */ 0 +}; + +const int Ps2Input::_padCodes[16] = { + SDLK_1, // Select + 0, // L3 + 0, // R3 + SDLK_F5, // Start + 0, // Up + 0, // Right + 0, // Down + 0, // Left + SDLK_KP0, // L2 + 0, // R2 + SDLK_n, // L1 + SDLK_y, // R1 + SDLK_ESCAPE, // Triangle + 0, // Circle => Right mouse button + 0, // Cross => Left mouse button + SDLK_RETURN // Square +}; + +const int Ps2Input::_padFlags[16] = { + 0, // Select + 0, // L3 + 0, // R3 + 0, // Start + 0, // Up + 0, // Right + 0, // Down + 0, // Left + 0, // L2 + 0, // R2 + 0, // L1 + 0, // R1 + 0, // Triangle + 0, // Circle + 0, // Cross + 0 // Square +}; + + diff --git a/backends/platform/ps2/ps2input.h b/backends/platform/ps2/ps2input.h new file mode 100644 index 0000000000..c7a29c7bfd --- /dev/null +++ b/backends/platform/ps2/ps2input.h @@ -0,0 +1,59 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __PS2INPUT_H__ +#define __PS2INPUT_H__ + +#include "common/system.h" + +class OSystem_PS2; +class Ps2Pad; + +class Ps2Input { +public: + Ps2Input(OSystem_PS2 *system, bool mouseLoaded, bool kbdLoaded); + ~Ps2Input(void); + void newRange(uint16 minx, uint16 miny, uint16 maxx, uint16 maxy); + bool pollEvent(OSystem::Event *event); + void warpTo(uint16 x, uint16 y); +private: + int mapKey(int key, int mod); + bool getKeyEvent(OSystem::Event *event, uint16 buttonCode, bool down); + OSystem_PS2 *_system; + Ps2Pad *_pad; + + uint16 _minx, _maxx, _miny, _maxy; + + uint16 _posX, _posY; + uint16 _mButtons; + uint16 _padLastButtons; + uint32 _lastPadCheck; + uint16 _padAccel; + + bool _mouseLoaded, _kbdLoaded; + int _keyFlags; + static const int _padCodes[16], _padFlags[16]; + static const int _usbToSdlk[0x100]; +}; + +#endif // __PS2INPUT_H__ + diff --git a/backends/platform/ps2/ps2mutex.cpp b/backends/platform/ps2/ps2mutex.cpp new file mode 100644 index 0000000000..6ae9a3a005 --- /dev/null +++ b/backends/platform/ps2/ps2mutex.cpp @@ -0,0 +1,85 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/ps2/systemps2.h" + +OSystem::MutexRef OSystem_PS2::createMutex(void) { + WaitSema(_mutexSema); + Ps2Mutex *mutex = NULL; + for (int i = 0; i < MAX_MUTEXES; i++) + if (_mutex[i].sema < 0) { + mutex = _mutex + i; + break; + } + if (mutex) { + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + mutex->sema = CreateSema(&newSema); + mutex->owner = mutex->count = 0; + } else + printf("OSystem_PS2::createMutex: ran out of Mutex slots!\n"); + SignalSema(_mutexSema); + return (OSystem::MutexRef)mutex; +} + +void OSystem_PS2::lockMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + int tid = GetThreadId(); + assert(tid != 0); + if (sysMutex->owner && (sysMutex->owner == tid)) + sysMutex->count++; + else { + SignalSema(_mutexSema); + WaitSema(sysMutex->sema); + WaitSema(_mutexSema); + sysMutex->owner = tid; + sysMutex->count = 0; + } + SignalSema(_mutexSema); +} + +void OSystem_PS2::unlockMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + int tid = GetThreadId(); + if (sysMutex->owner && sysMutex->count && (sysMutex->owner == tid)) + sysMutex->count--; + else { + assert(sysMutex->count == 0); + SignalSema(sysMutex->sema); + sysMutex->owner = 0; + } + SignalSema(_mutexSema); +} + +void OSystem_PS2::deleteMutex(MutexRef mutex) { + WaitSema(_mutexSema); + Ps2Mutex *sysMutex = (Ps2Mutex*)mutex; + if (sysMutex->owner || sysMutex->count) + printf("WARNING: Deleting LOCKED mutex!\n"); + DeleteSema(sysMutex->sema); + sysMutex->sema = -1; + SignalSema(_mutexSema); +} + diff --git a/backends/platform/ps2/ps2pad.cpp b/backends/platform/ps2/ps2pad.cpp new file mode 100644 index 0000000000..8394a421db --- /dev/null +++ b/backends/platform/ps2/ps2pad.cpp @@ -0,0 +1,150 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <kernel.h> +#include <malloc.h> +#include <assert.h> +#include "backends/ps2/systemps2.h" +#include "backends/ps2/ps2pad.h" + +Ps2Pad::Ps2Pad(OSystem_PS2 *system) { + _system = system; + _padBuf = (uint8*)memalign(64, 256); + _padStatus = STAT_NONE; + + padInit(0); // initialize library + _port = _slot = 0; // first controller, no multitap + initPad(); +} + +void Ps2Pad::initPad(void) { + int modes = 0; + if (_padStatus == STAT_NONE) { + if (padPortOpen(_port, _slot, _padBuf) == 1) { + _padStatus = STAT_OPEN; + _padInitTime = _system->getMillis(); + } else { + padPortClose(_port, _slot); + printf("Unable to open port (%d/%d)!\n", _port, _slot); + } + } else { + if (checkPadReady(_port, _slot)) { + switch (_padStatus) { + case STAT_OPEN: + _padStatus = STAT_DETECT; + break; + case STAT_DETECT: + _isDualShock = false; + modes = padInfoMode(_port, _slot, PAD_MODETABLE, -1); + + // Verify that the controller has a DUAL SHOCK mode + for (int cnt = 0; cnt < modes; cnt++) + if (padInfoMode(_port, _slot, PAD_MODETABLE, cnt) == PAD_TYPE_DUALSHOCK) + _isDualShock = true; + + // If ExId != 0x0 => This controller has actuator engines + // This check should always pass if the Dual Shock test above passed + if (_isDualShock) + if (padInfoMode(_port, _slot, PAD_MODECUREXID, 0) == 0) + _isDualShock = false; + + if (_isDualShock) { + // When using MMODE_LOCK, user cant change mode with Select button + padSetMainMode(_port, _slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); + _padStatus = STAT_INIT_DSHOCK; + } else + _padStatus = STAT_WAIT_READY; + break; + case STAT_INIT_DSHOCK: + padEnterPressMode(_port, _slot); + _padStatus = STAT_CHECK_ACT; + break; + case STAT_CHECK_ACT: + _actuators = padInfoAct(_port, _slot, -1, 0); + if (_actuators != 0) + _padStatus = STAT_INIT_ACT; + else { + _isDualShock = false; + _padStatus = STAT_WAIT_READY; + } + break; + case STAT_INIT_ACT: + char actAlign[6]; + actAlign[0] = 0; + actAlign[1] = 1; + actAlign[2] = actAlign[3] = actAlign[4] = actAlign[5] = 0xff; + padSetActAlign(_port, _slot, actAlign); + _padStatus = STAT_WAIT_READY; + break; + case STAT_WAIT_READY: + _padStatus = STAT_OKAY; + break; + case STAT_OKAY: + // pad is already initialized + break; + } + } else { + // check for timeout... + if (_system->getMillis() - _padInitTime > 5000) { + // still no pad, give up. + if (padPortClose(_port, _slot) != 1) + printf("WARNING: can't close port: %d/%d\n", _port, _slot); + printf("looking for pad, gave up and closed port\n"); + _padStatus = STAT_NONE; + } + } + } +} + +bool Ps2Pad::checkPadReady(int port, int slot) { + int state = padGetState(port, slot); + return (state == PAD_STATE_STABLE) || (state == PAD_STATE_FINDCTP1); +} + +bool Ps2Pad::padAlive(void) { + if ((_padStatus == STAT_OKAY) && checkPadReady(_port, _slot)) + return true; + initPad(); + return false; +} + +bool Ps2Pad::isDualShock(void) { + return _isDualShock; +} + +void Ps2Pad::readPad(uint16 *pbuttons, int16 *joyh, int16 *joyv) { + if (padAlive()) { + struct padButtonStatus buttons; + padRead(_port, _slot, &buttons); + *pbuttons = ~buttons.btns; + if (_isDualShock) { + *joyh = (int16)buttons.ljoy_h - 128; + *joyv = (int16)buttons.ljoy_v - 128; + } else + *joyh = *joyv = 0; + } else { + *joyh = *joyv = 0; + *pbuttons = 0; + } +} + + diff --git a/backends/platform/ps2/ps2pad.h b/backends/platform/ps2/ps2pad.h new file mode 100644 index 0000000000..0e2994aafe --- /dev/null +++ b/backends/platform/ps2/ps2pad.h @@ -0,0 +1,66 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __PS2PAD_H__ +#define __PS2PAD_H__ + +enum PadStatus { + STAT_NONE, + STAT_OPEN, + STAT_DETECT, + STAT_INIT_DSHOCK, + STAT_CHECK_ACT, + STAT_INIT_ACT, + STAT_WAIT_READY, + STAT_OKAY +}; + +#include "common/system.h" +#include <libpad.h> + +#define PAD_DIR_MASK (PAD_LEFT | PAD_DOWN | PAD_RIGHT | PAD_UP) +#define PAD_BUTTON_MASK (PAD_START | PAD_SELECT | PAD_SQUARE | PAD_CROSS | PAD_CIRCLE | PAD_TRIANGLE) + +class OSystem_PS2; + +class Ps2Pad { +public: + Ps2Pad(OSystem_PS2 *system); + bool padAlive(void); + bool isDualShock(void); + void readPad(uint16 *pbuttons, int16 *joyh, int16 *joyv); +private: + void initPad(void); + bool checkPadReady(int port, int slot); + + OSystem_PS2 *_system; + int _port, _slot; + + uint32 _padInitTime; + PadStatus _padStatus; + bool _isDualShock; + uint8 *_padBuf; + char _actuators; +}; + +#endif //__PS2PAD_H__ + diff --git a/backends/platform/ps2/ps2time.cpp b/backends/platform/ps2/ps2time.cpp new file mode 100644 index 0000000000..bfccfe1300 --- /dev/null +++ b/backends/platform/ps2/ps2time.cpp @@ -0,0 +1,126 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/ps2/systemps2.h" +#include "eecodyvdfs.h" +#include <osd_config.h> +#define FROM_BCD(a) ((a >> 4) * 10 + (a & 0xF)) + +static int g_timeSecs; +static int g_day, g_month, g_year; +static int g_lastTimeCheck; +extern volatile uint32 msecCount; + +void buildNewDate(int dayDiff) { + static int daysPerMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + if (((g_year % 4) == 0) && (((g_year % 100) != 0) || ((g_year % 1000) == 0))) + daysPerMonth[1] = 29; + else + daysPerMonth[1] = 28; + + if (dayDiff == -1) { + g_day--; + if (g_day == 0) { + g_month--; + if (g_month == 0) { + g_year--; + g_month = 12; + } + g_day = daysPerMonth[g_month - 1]; + } + } else if (dayDiff == 1) { + g_day++; + if (g_day > daysPerMonth[g_month - 1]) { + g_day = 1; + g_month++; + if (g_month > 12) { + g_month = 1; + g_year++; + } + } + } +} + +#define SECONDS_PER_DAY (24 * 60 * 60) + +void OSystem_PS2::readRtcTime(void) { + struct CdClock cdClock; + readRTC(&cdClock); + + g_lastTimeCheck = getMillis(); + + if (cdClock.stat) { + msgPrintf(5000, "Unable to read RTC time, EC: %d\n", cdClock.stat); + g_day = g_month = 1; + g_year = 0; + g_timeSecs = 0; + } else { + int gmtOfs = configGetTimezone(); + if (configIsDaylightSavingEnabled()) + gmtOfs += 60; + + int timeSecs = (FROM_BCD(cdClock.hour) * 60 + FROM_BCD(cdClock.minute)) * 60 + FROM_BCD(cdClock.second); + timeSecs -= 9 * 60 * 60; // minus 9 hours, JST -> GMT conversion + timeSecs += gmtOfs * 60; // GMT -> timezone the user selected + + g_day = FROM_BCD(cdClock.day); + g_month = FROM_BCD(cdClock.month); + g_year = FROM_BCD(cdClock.year); + + if (timeSecs < 0) { + buildNewDate(-1); + timeSecs += SECONDS_PER_DAY; + } else if (timeSecs >= SECONDS_PER_DAY) { + buildNewDate(+1); + timeSecs -= SECONDS_PER_DAY; + } + g_timeSecs = (uint32)timeSecs; + } + + sioprintf("Time: %d:%02d:%02d - %d.%d.%4d", g_timeSecs / (60 * 60), (g_timeSecs / 60) % 60, g_timeSecs % 60, + g_day, g_month, g_year + 2000); +} + +extern "C" time_t time(time_t *p) { + return (time_t)g_timeSecs; +} + +extern "C" struct tm *localtime(const time_t *p) { + uint32 currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; + if (currentSecs >= SECONDS_PER_DAY) { + buildNewDate(+1); + g_lastTimeCheck += SECONDS_PER_DAY * 1000; + currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; + } + + static struct tm retStruct; + memset(&retStruct, 0, sizeof(retStruct)); + + retStruct.tm_hour = currentSecs / (60 * 60); + retStruct.tm_min = (currentSecs / 60) % 60; + retStruct.tm_sec = currentSecs % 60; + retStruct.tm_year = g_year + 100; + retStruct.tm_mday = g_day; + retStruct.tm_mon = g_month - 1; + // tm_wday, tm_yday and tm_isdst are zero for now + return &retStruct; +} diff --git a/backends/platform/ps2/savefile.cpp b/backends/platform/ps2/savefile.cpp new file mode 100644 index 0000000000..495fc556b3 --- /dev/null +++ b/backends/platform/ps2/savefile.cpp @@ -0,0 +1,801 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include <tamtypes.h> +#include <kernel.h> +#include <sifrpc.h> +#include <loadfile.h> +#include <fileio.h> +#include <malloc.h> +#include <ucl/ucl.h> +#include <libmc.h> +#include "backends/ps2/savefile.h" +#include "backends/ps2/Gs2dScreen.h" +#include "backends/ps2/systemps2.h" +#include "common/scummsys.h" + +extern void *_gp; + +#define UCL_MAGIC 0x314C4355 + +#define PORT 0 +#define SLOT 0 +// port 0, slot 0: memory card in first slot. + +void sioprintf(const char *zFormat, ...); + +class McAccess { +public: + McAccess(int port, int slot); + ~McAccess(void); + int open(const char *name, int mode); + int close(int fd); + int size(int fd); + int read(int fd, void *buf, int size); + int write(int fd, const void *buf, int size); + int mkDir(const char *name); + int getDir(const char *name, unsigned int mode, int max, void *dest); + int getInfo(int *type, int *free, int *format); + int remove(const char *name); +private: + int _sema; + int _port, _slot; +}; + +McAccess::McAccess(int port, int slot) { + _port = port; + _slot = slot; + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _sema = CreateSema(&newSema); + + assert(mcInit(MC_TYPE_MC) >= 0); +} + +McAccess::~McAccess(void) { + DeleteSema(_sema); +} + +int McAccess::open(const char *name, int mode) { + int res; + WaitSema(_sema); + mcOpen(_port, _slot, name, mode); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::close(int fd) { + int res; + WaitSema(_sema); + mcClose(fd); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::size(int fd) { + int res, size; + WaitSema(_sema); + mcSeek(fd, 0, SEEK_END); + mcSync(0, NULL, &size); + mcSeek(fd, 0, SEEK_SET); + mcSync(0, NULL, &res); + SignalSema(_sema); + assert(res == 0); + return size; +} + +int McAccess::read(int fd, void *buf, int size) { + int res; + WaitSema(_sema); + mcRead(fd, buf, size); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::write(int fd, const void *buf, int size) { + int res; + WaitSema(_sema); + mcWrite(fd, buf, size); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::mkDir(const char *name) { + int res; + WaitSema(_sema); + mcMkDir(_port, _slot, name); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::remove(const char *name) { + int res; + WaitSema(_sema); + mcDelete(_port, _slot, name); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::getDir(const char *name, unsigned int mode, int max, void *dest) { + int res; + WaitSema(_sema); + mcGetDir(_port, _slot, name, mode, max, (mcTable*)dest); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +int McAccess::getInfo(int *type, int *free, int *format) { + int res; + WaitSema(_sema); + mcGetInfo(_port, _slot, type, free, format); + mcSync(0, NULL, &res); + SignalSema(_sema); + return res; +} + +class UclOutSaveFile : public Common::OutSaveFile { +public: + UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc); + virtual ~UclOutSaveFile(void); + virtual uint32 write(const void *ptr, uint32 size); + virtual void flush(void); + virtual bool ioFailed(void) const; + virtual void clearIOFailed(void); +private: + OSystem_PS2 *_system; + Gs2dScreen *_screen; + McAccess *_mc; + int _fd; + uint8 *_buf; + uint32 _bufSize, _bufPos; + bool _ioFailed, _wasFlushed; + char _fileName[128]; +}; + +class UclInSaveFile : public Common::InSaveFile { +public: + UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mc); + virtual ~UclInSaveFile(void); + virtual bool eos(void) const; + virtual uint32 read(void *ptr, uint32 size); + virtual bool ioFailed(void) const; + virtual void clearIOFailed(void); + virtual void skip(uint32 offset); + + virtual uint32 pos(void) const; + virtual uint32 size(void) const; + virtual void seek(int pos, int whence = SEEK_SET); +private: + Gs2dScreen *_screen; + McAccess *_mc; + uint8 *_buf; + uint32 _bufSize, _bufPos; + bool _ioFailed; +}; + +class AutoSaveFile : public Common::OutSaveFile { +public: + AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename); + ~AutoSaveFile(void); + virtual uint32 write(const void *ptr, uint32 size); + virtual void flush(void) { }; + virtual bool ioFailed(void) { return false; }; + virtual void clearIOFailed(void) {}; +private: + Ps2SaveFileManager *_saveMan; + char _fileName[256]; + uint8 *_buf; + uint32 _bufSize, _bufPos; +}; + +AutoSaveFile::AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename) { + strcpy(_fileName, filename); + _saveMan = saveMan; + _bufSize = 65536; + _buf = (uint8*)memalign(64, _bufSize); + _bufPos = 0; +} + +AutoSaveFile::~AutoSaveFile(void) { + _saveMan->writeSaveNonblocking(_fileName, _buf, _bufPos); + free(_buf); +} + +uint32 AutoSaveFile::write(const void *ptr, uint32 size) { + uint32 bytesFree = _bufSize - _bufPos; + if (bytesFree < size) { + uint32 allocBytes = (size > 32 * 1024) ? size : 32 * 1024; + _bufSize += allocBytes; + _buf = (uint8*)realloc(_buf, _bufSize); + bytesFree = _bufSize - _bufPos; + } + memcpy(_buf + _bufPos, ptr, size); + _bufPos += size; + return size; +} + +#define MAX_MC_ENTRIES 16 + +void runSaveThread(Ps2SaveFileManager *param); + +Ps2SaveFileManager::Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen) { + _system = system; + _screen = screen; + _mc = new McAccess(0, 0); + + _mcDirList = (mcTable*)memalign(64, MAX_MC_ENTRIES * sizeof(mcTable)); + _mcDirName[0] = '\0'; + _mcCheckTime = 0; + _mcNeedsUpdate = true; + + for (int mcCheckCount = 0; mcCheckCount < 3; mcCheckCount++) { + /* retry mcGetInfo 3 times. It slows down startup without mc considerably, + but cheap 3rd party memory cards apparently fail to get detected once in a while */ + + int mcType, mcFree, mcFormat; + int res = _mc->getInfo(&mcType, &mcFree, &mcFormat); + + if ((res == 0) || (res == -1)) { // mc okay + _mcPresent = true; + printf("MC okay, result = %d. Type %d, Free %d, Format %d\n", res, mcType, mcFree, mcFormat); + checkMainDirectory(); + break; + } else { + _mcPresent = false; + printf("MC failed, not present or not formatted, code %d\n", res); + } + } + + // create save thread + ee_sema_t newSema; + newSema.init_count = 0; + newSema.max_count = 1; + _autoSaveSignal = CreateSema(&newSema); + _autoSaveBuf = NULL; + _autoSaveSize = 0; + _systemQuit = false; + + ee_thread_t saveThread, thisThread; + ReferThreadStatus(GetThreadId(), &thisThread); + + saveThread.initial_priority = thisThread.current_priority + 1; + saveThread.stack_size = 8 * 1024; + _autoSaveStack = malloc(saveThread.stack_size); + saveThread.stack = _autoSaveStack; + saveThread.func = (void *)runSaveThread; + saveThread.gp_reg = &_gp; + + _autoSaveTid = CreateThread(&saveThread); + assert(_autoSaveTid >= 0); + StartThread(_autoSaveTid, this); +} + +Ps2SaveFileManager::~Ps2SaveFileManager(void) { +} + +void Ps2SaveFileManager::checkMainDirectory(void) { + // verify that the main directory (scummvm config + icon) exists + int ret, fd; + _mcNeedsUpdate = true; + ret = _mc->getDir("/ScummVM/*", 0, MAX_MC_ENTRIES, _mcDirList); + printf("/ScummVM/* res = %d\n", ret); + if (ret <= 0) { // assume directory doesn't exist + printf("Dir doesn't exist\n"); + ret = _mc->mkDir("/ScummVM"); + if (ret >= 0) { + fd = _mc->open("/ScummVM/scummvm.icn", O_WRONLY | O_CREAT); + if (fd >= 0) { + uint16 icoSize; + uint16 *icoBuf = decompressIconData(&icoSize); + ret = _mc->write(fd, icoBuf, icoSize * 2); + _mc->close(fd); + free(icoBuf); + + printf(".icn written\n"); + setupIcon("/ScummVM/icon.sys", "scummvm.icn", "ScummVM", "Configuration"); + } else + printf("Can't create icon file: %d\n", fd); + } else + printf("can't create scummvm directory: %d\n", ret); + } +} + +void Ps2SaveFileManager::splitPath(const char *fileName, char *dir, char *name) { + strcpy(dir, fileName); + char *ext = strchr(dir, '.'); + if (ext) { + *ext = '\0'; + ext++; + } + if (ext && *ext) + sprintf(name, "%s.ucl", ext); + else + strcpy(name, "save.ucl"); +} + +bool Ps2SaveFileManager::mcReadyForDir(const char *dir) { + if (_mcNeedsUpdate || ((_system->getMillis() - _mcCheckTime) > 2000) || !_mcPresent) { + // check if memory card was exchanged/removed in the meantime + int mcType, mcFree, mcFormat, mcResult; + mcResult = _mc->getInfo(&mcType, &mcFree, &mcFormat); + if (mcResult != 0) { // memory card was exchanged + _mcNeedsUpdate = true; + if (mcResult == -1) { // yes, it was exchanged + checkMainDirectory(); // make sure ScummVM dir and icon are there + } else { // no memorycard in slot or not formatted or something like that + _mcPresent = false; + printf("MC not found, error code %d\n", mcResult); + return false; + } + } + _mcPresent = true; + _mcCheckTime = _system->getMillis(); + } + if (_mcNeedsUpdate || strcmp(_mcDirName, dir)) { + strcpy(_mcDirName, dir); + char dirStr[256]; + sprintf(dirStr, "/ScummVM-%s/*", dir); + _mcEntries = _mc->getDir(dirStr, 0, MAX_MC_ENTRIES, _mcDirList); + _mcNeedsUpdate = false; + } + return (_mcEntries >= 0); +} + +Common::InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { + _screen->wantAnim(true); + + char dir[256], name[256]; + splitPath(filename, dir, name); + if (mcReadyForDir(dir)) { + bool fileExists = false; + for (int i = 0; i < _mcEntries; i++) + if (strcmp(name, (char*)_mcDirList[i].name) == 0) + fileExists = true; + if (fileExists) { + char fullName[256]; + sprintf(fullName, "/ScummVM-%s/%s", dir, name); + UclInSaveFile *file = new UclInSaveFile(fullName, _screen, _mc); + if (file) { + if (!file->ioFailed()) + return file; + else + delete file; + } + } else + printf("file %s (%s) doesn't exist\n", filename, name); + } + _screen->wantAnim(false); + return NULL; +} + +Common::OutSaveFile *Ps2SaveFileManager::openForSaving(const char *filename) { + int res; + char dir[256], name[256]; + + _screen->wantAnim(true); + splitPath(filename, dir, name); + + if (!mcReadyForDir(dir)) { + if (_mcPresent) { // directory doesn't seem to exist yet + char fullPath[256]; + sprintf(fullPath, "/ScummVM-%s", dir); + res = _mc->mkDir(fullPath); + + char icoSysDest[256], saveDesc[256]; + sprintf(icoSysDest, "%s/icon.sys", fullPath); + strcpy(saveDesc, dir); + if ((saveDesc[0] >= 'a') && (saveDesc[0] <= 'z')) + saveDesc[0] += 'A' - 'a'; + setupIcon(icoSysDest, "../ScummVM/scummvm.icn", saveDesc, "Savegames"); + } + } + + if (_mcPresent) { + char fullPath[256]; + sprintf(fullPath, "/ScummVM-%s/%s", dir, name); + if (strstr(filename, ".s00") || strstr(filename, ".ASD") || strstr(filename, ".asd")) { + // this is an autosave + AutoSaveFile *file = new AutoSaveFile(this, fullPath); + return file; + } else { + UclOutSaveFile *file = new UclOutSaveFile(fullPath, _system, _screen, _mc); + if (!file->ioFailed()) { + // we're creating a file, mc will have to be updated next time + _mcNeedsUpdate = true; + return file; + } else + delete file; + } + } + + _screen->wantAnim(false); + return NULL; +} + +void Ps2SaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) { + _screen->wantAnim(true); + + int mcType, mcFree, mcFormat, mcResult; + mcResult = _mc->getInfo(&mcType, &mcFree, &mcFormat); + + memset(marks, false, num * sizeof(bool)); + + if ((mcResult == 0) || (mcResult == -1)) { + // there's a memory card in the slot. + if (mcResult == -1) + _mcNeedsUpdate = true; + + mcTable *mcEntries = (mcTable*)memalign(64, sizeof(mcTable) * MAX_MC_ENTRIES); + + char dirStr[256], ext[256], mcSearchStr[256]; + strcpy(dirStr, prefix); + char *pos = strchr(dirStr, '.'); + if (pos) { + strcpy(ext, pos + 1); + *pos = '\0'; + } else + ext[0] = '\0'; + sprintf(mcSearchStr, "/ScummVM-%s/%s*", dirStr, ext); + + int numEntries = _mc->getDir(mcSearchStr, 0, MAX_MC_ENTRIES, mcEntries); + + int searchLen = strlen(ext); + for (int i = 0; i < numEntries; i++) + if ((((char*)mcEntries[i].name)[0] != '.') && stricmp((char*)mcEntries[i].name, "icon.sys")) { + char *stopCh; + int destNum = (int)strtoul((char*)mcEntries[i].name + searchLen, &stopCh, 10); + if ((!stopCh) || strcmp(stopCh, ".ucl")) + printf("unexpected end %s in name %s, search %s\n", stopCh, (char*)mcEntries[i].name, prefix); + if (destNum < num) + marks[destNum] = true; + } + free(mcEntries); + } + _screen->wantAnim(false); +} + +const char *Ps2SaveFileManager::getSavePath(void) const { + return "mc0:"; +} + +bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2) { + mcIcon icon_sys; + memset(&icon_sys, 0, sizeof(mcIcon)); + memcpy(icon_sys.head, "PS2D", 4); + char title[256]; + if (!stricmp("SAVEGAME", descr1)) { // these are broken sword 1 savegames + sprintf(title, "BSword1\n%s", descr2); + icon_sys.nlOffset = 8; + } else { + sprintf(title, "%s\n%s", descr1, descr2); + icon_sys.nlOffset = strlen(descr1) + 1; + } + strcpy_sjis((short*)&(icon_sys.title), title); + icon_sys.trans = 0x10; + memcpy(icon_sys.bgCol, _bgcolor, sizeof(_bgcolor)); + memcpy(icon_sys.lightDir, _lightdir, sizeof(_lightdir)); + memcpy(icon_sys.lightCol, _lightcol, sizeof(_lightcol)); + memcpy(icon_sys.lightAmbient, _ambient, sizeof(_ambient)); + strcpy((char*)icon_sys.view, ico); + strcpy((char*)icon_sys.copy, ico); + strcpy((char*)icon_sys.del, ico); + + int fd, res; + fd = _mc->open(dest, O_WRONLY | O_CREAT); + if (fd >= 0) { + res = _mc->write(fd, &icon_sys, sizeof(icon_sys)); + _mc->close(fd); + return (res == sizeof(icon_sys)); + } else + return false; +} + +uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { + uint16 inPos = 1; + uint16 *rleData = (uint16*)_rleIcoData; + uint16 resSize = rleData[0]; + uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16)); + uint16 outPos = 0; + while (outPos < resSize) { + uint16 len = rleData[inPos++]; + while (len--) + resData[outPos++] = 0x7FFF; + len = rleData[inPos++]; + while (len--) + resData[outPos++] = rleData[inPos++]; + } + *size = resSize; + assert(outPos == resSize); + return resData; +} + +void runSaveThread(Ps2SaveFileManager *param) { + param->saveThread(); +} + +void Ps2SaveFileManager::writeSaveNonblocking(char *name, void *buf, uint32 size) { + if (buf && size && !_systemQuit) { + strcpy(_autoSaveName, name); + assert(!_autoSaveBuf); + _autoSaveBuf = (uint8*)malloc(size); + memcpy(_autoSaveBuf, buf, size); + _autoSaveSize = size; + SignalSema(_autoSaveSignal); + } +} + +void Ps2SaveFileManager::saveThread(void) { + while (!_systemQuit) { + WaitSema(_autoSaveSignal); + if (_autoSaveBuf && _autoSaveSize) { + UclOutSaveFile *outSave = new UclOutSaveFile(_autoSaveName, _system, _screen, _mc); + if (!outSave->ioFailed()) { + outSave->write(_autoSaveBuf, _autoSaveSize); + outSave->flush(); + } + if (outSave->ioFailed()) + _system->msgPrintf(5000, "Writing autosave to %s failed", _autoSaveName); + delete outSave; + free(_autoSaveBuf); + _autoSaveBuf = NULL; + _autoSaveSize = 0; + _mcNeedsUpdate = true; // we've created a file, mc will have to be updated + _screen->wantAnim(false); + } + } + ExitThread(); +} + +void Ps2SaveFileManager::quit(void) { + _systemQuit = true; + ee_thread_t statSave, statThis; + ReferThreadStatus(GetThreadId(), &statThis); + ChangeThreadPriority(_autoSaveTid, statThis.current_priority - 1); + + do { // wait until thread called ExitThread() + SignalSema(_autoSaveSignal); + ReferThreadStatus(_autoSaveTid, &statSave); + } while (statSave.status != 0x10); + + DeleteThread(_autoSaveTid); + free(_autoSaveStack); +} + +UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mc) { + _screen = screen; + _mc = mc; + int fd = _mc->open(filename, O_RDONLY); + _buf = NULL; + _bufSize = _bufPos = 0; + _ioFailed = false; + + if (fd >= 0) { + int srcSize = _mc->size(fd); + if (srcSize > 8) { + int res; + uint8 *tmpBuf = (uint8*)memalign(64, srcSize); + res = _mc->read(fd, tmpBuf, srcSize); + if ((res == srcSize) && (*(uint32*)tmpBuf == UCL_MAGIC)) { + uint32 resLen = _bufSize = *(uint32*)(tmpBuf + 4); + _buf = (uint8*)malloc(_bufSize + 2048); + res = ucl_nrv2e_decompress_8(tmpBuf + 8, srcSize - 8, _buf, &resLen, NULL); + if ((res < 0) || (resLen != _bufSize)) { + printf("Unable to decompress file %s (%d -> %d) error code %d\n", filename, srcSize, _bufSize, res); + free(_buf); + _buf = NULL; + _bufSize = 0; + } + } + free(tmpBuf); + } + _mc->close(fd); + } + if (!_buf) { + printf("Invalid savegame %s\n", filename); + _ioFailed = true; + } +} + +UclInSaveFile::~UclInSaveFile(void) { + if (_buf) + free(_buf); + _screen->wantAnim(false); +} + +bool UclInSaveFile::ioFailed(void) const { + return _ioFailed; +} + +void UclInSaveFile::clearIOFailed(void) { + _ioFailed = false; +} + +bool UclInSaveFile::eos(void) const { + return _bufPos == _bufSize; +} + +uint32 UclInSaveFile::pos(void) const { + return _bufPos; +} + +uint32 UclInSaveFile::size(void) const { + return _bufSize; +} + +void UclInSaveFile::seek(int pos, int whence) { + int destPos; + switch (whence) { + case SEEK_SET: + destPos = pos; + break; + case SEEK_CUR: + destPos = _bufPos + pos; + break; + case SEEK_END: + destPos = _bufSize + pos; + break; + default: + return; + } + if ((destPos >= 0) && (destPos <= (int)_bufSize)) + _bufPos = (uint32)destPos; +} + +uint32 UclInSaveFile::read(void *ptr, uint32 size) { + if (_buf) { + uint32 bytesRemain = _bufSize - _bufPos; + if (size > bytesRemain) { + size = bytesRemain; + _ioFailed = true; + } + memcpy(ptr, _buf + _bufPos, size); + _bufPos += size; + return size; + } else { + _ioFailed = true; + return 0; + } +} + +void UclInSaveFile::skip(uint32 offset) { + if (_buf) { + if (_bufPos + offset <= _bufSize) + _bufPos += offset; + else + _bufPos = _bufSize; + } +} + +UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc) { + _screen = screen; + _system = system; + _mc = mc; + _bufPos = 0; + _fd = _mc->open(filename, O_WRONLY | O_CREAT); + if (_fd >= 0) { + _bufSize = 65536; + _buf = (uint8*)malloc(_bufSize); + _ioFailed = false; + strcpy(_fileName, filename); + } else { + _ioFailed = true; + _bufSize = 0; + _buf = NULL; + } + _wasFlushed = false; +} + +UclOutSaveFile::~UclOutSaveFile(void) { + if (_buf) { + if (_bufPos) { + printf("Engine didn't call SaveFile::flush()\n"); + flush(); + if (ioFailed()) { + // unable to save to memory card and it's too late to return an error code to the engine + _system->msgPrintf(5000, "!WARNING!\nCan't write to memory card.\nGame was NOT saved."); + printf("~UclOutSaveFile: Flush failed!\n"); + } + } + free(_buf); + } + if (_fd >= 0) + _mc->close(_fd); + _screen->wantAnim(false); +} + +bool UclOutSaveFile::ioFailed(void) const { + return _ioFailed; +} + +void UclOutSaveFile::clearIOFailed(void) { + _ioFailed = false; +} + +void UclOutSaveFile::flush(void) { + int res; + + if (_bufPos) { + if (_wasFlushed) { + // the engine flushed this file and afterwards wrote more data. + // this is unsupported because it results in savefiles that consist + // of two or more compressed segments. + printf("Error: 2nd call to UclOutSaveFile::flush!\n"); + res = -1; + } else { + uint32 compSize = _bufPos * 2; + uint8 *compBuf = (uint8*)memalign(64, compSize + 8); + *(uint32*)(compBuf + 0) = UCL_MAGIC; + *(uint32*)(compBuf + 4) = _bufPos; // uncompressed size + res = ucl_nrv2e_99_compress(_buf, _bufPos, compBuf + 8, &compSize, NULL, 10, NULL, NULL); + if (res >= 0) { + res = _mc->write(_fd, compBuf, compSize + 8); + if (res != (int)compSize + 8) { + printf("flush: write failed, %d != %d\n", res, compSize + 8); + res = -1; + } + } else + printf("Unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + free(compBuf); + _bufPos = 0; + } + + if (res < 0) { + _ioFailed = true; + printf("UclOutSaveFile::flush failed!\n"); + if (_fd >= 0) { + // the file is broken; delete it + _mc->close(_fd); + res = _mc->remove(_fileName); + if (res == 0) + printf("File %s: remove ok\n", _fileName); + else + printf("File %s: remove error %d\n", _fileName, res); + _fd = -1; + } + } + } +} + +uint32 UclOutSaveFile::write(const void *ptr, uint32 size) { + assert(_bufPos <= _bufSize); + uint32 bytesFree = _bufSize - _bufPos; + if (bytesFree < size) { + uint32 allocBytes = (size > 32 * 1024) ? size : 32 * 1024; + _bufSize += allocBytes; + _buf = (uint8*)realloc(_buf, _bufSize); + bytesFree = _bufSize - _bufPos; + } + assert(bytesFree >= size); + memcpy(_buf + _bufPos, ptr, size); + _bufPos += size; + return size; +} + + diff --git a/backends/platform/ps2/savefile.h b/backends/platform/ps2/savefile.h new file mode 100644 index 0000000000..aafb124ad0 --- /dev/null +++ b/backends/platform/ps2/savefile.h @@ -0,0 +1,80 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __PS2_SAVEFILE__ +#define __PS2_SAVEFILE__ + +#include <libmc.h> +#include "common/savefile.h" + +class Gs2dScreen; +class OSystem_PS2; +class McAccess; + +class Ps2SaveFileManager : public Common::SaveFileManager { +public: + Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen); + virtual ~Ps2SaveFileManager(); + + virtual Common::InSaveFile *openForLoading(const char *filename); + virtual Common::OutSaveFile *openForSaving(const char *filename); + virtual void listSavefiles(const char *prefix, bool *marks, int num); + + /** Get the path to the save game directory. */ + virtual const char *getSavePath() const; + + void writeSaveNonblocking(char *name, void *buf, uint32 size); + void saveThread(void); + void quit(void); +private: + bool setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2); + + bool mcReadyForDir(const char *dir); + + void checkMainDirectory(void); + void splitPath(const char *fileName, char *dir, char *name); + uint16 *decompressIconData(uint16 *size); + + Gs2dScreen *_screen; + OSystem_PS2 *_system; + McAccess *_mc; + + int _autoSaveTid; + int _autoSaveSignal; + void *_autoSaveStack; + volatile bool _systemQuit; + uint8 *_autoSaveBuf; + uint32 _autoSaveSize; + char _autoSaveName[256]; + + mcTable *_mcDirList; + int _mcEntries; + char _mcDirName[256]; + bool _mcNeedsUpdate, _mcPresent; + uint32 _mcCheckTime; + + static const uint8 _rleIcoData[14018]; + static const iconIVECTOR _bgcolor[4]; + static const iconFVECTOR _lightdir[3], _lightcol[3], _ambient; +}; + +#endif // __PS2_SAVEFILE__ diff --git a/backends/platform/ps2/sdlkeys.h b/backends/platform/ps2/sdlkeys.h new file mode 100644 index 0000000000..b2f783cedd --- /dev/null +++ b/backends/platform/ps2/sdlkeys.h @@ -0,0 +1,264 @@ +/* copied from SDK_keysym.h */ + +#ifndef __SDLKEYS_H__ +#define __SDLKEYS_H__ + +enum SdlKeyCodes { + 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, + /* + Skip uppercase letters + */ + 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, + /* End of ASCII mapped keysyms */ + + /* International keyboard syms */ + SDLK_WORLD_0 = 160, /* 0xA0 */ + 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, /* 0xFF */ + + /* Numeric keypad */ + 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, + + /* Arrows + Home/End pad */ + 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, + + /* Function keys */ + 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, + + /* Key state modifier keys */ + 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, /* Left "Windows" key */ + SDLK_RSUPER = 312, /* Right "Windows" key */ + SDLK_MODE = 313, /* "Alt Gr" key */ + SDLK_COMPOSE = 314, /* Multi-key compose key */ + + /* Miscellaneous function keys */ + SDLK_HELP = 315, + SDLK_PRINT = 316, + SDLK_SYSREQ = 317, + SDLK_BREAK = 318, + SDLK_MENU = 319, + SDLK_POWER = 320, /* Power Macintosh power key */ + SDLK_EURO = 321, /* Some european keyboards */ + SDLK_UNDO = 322, /* Atari keyboard has Undo */ + + /* Add any other keys here */ + + SDLK_LAST +}; + +#endif + + diff --git a/backends/platform/ps2/sysdefs.h b/backends/platform/ps2/sysdefs.h new file mode 100644 index 0000000000..086c75162c --- /dev/null +++ b/backends/platform/ps2/sysdefs.h @@ -0,0 +1,72 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef __SYSDEFS_H__ +#define __SYSDEFS_H__ + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long uint64; +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef signed long int64; + +enum Interrupts { + INT_GS = 0, + INT_VBLANK_START = 2, + INT_VBLANK_END = 3, + INT_TIMER0 = 9 +}; + +// dma 2 registers +#define D2_CHCR (*(volatile uint32*)0x1000A000) +#define D2_QWC (*(volatile uint32*)0x1000A020) +#define D2_TADR (*(volatile uint32*)0x1000A030) +#define D2_MADR (*(volatile uint32*)0x1000A010) +#define D2_ASR1 (*(volatile uint32*)0x1000A050) +#define D2_ASR0 (*(volatile uint32*)0x1000A040) + +#define D_CTRL (*(volatile uint32*)0x1000E000) +#define D_STAT (*(volatile uint32*)0x1000E010) +#define D_PCR (*(volatile uint32*)0x1000E020) +#define D_SQWC (*(volatile uint32*)0x1000E030) +#define D_RBSR (*(volatile uint32*)0x1000E040) +#define D_RBOR (*(volatile uint32*)0x1000E050) +#define D_STADR (*(volatile uint32*)0x1000E060) + +#define CIM2 (1 << 18) +#define CIS2 (1 << 2) + + +// timer 0 registers +#define T0_COUNT (*(volatile uint32*)0x10000000) +#define T0_MODE (*(volatile uint32*)0x10000010) +#define T0_COMP (*(volatile uint32*)0x10000020) +#define T0_HOLD (*(volatile uint32*)0x10000030) + +#define TIMER_MODE(clks, gate, gates, gatem, zeroret, cue, cmpe, ovfe, equf, ovff) \ + ((clks) | ((gate) << 2) | ((gates) << 3) | ((gatem) << 4) | ((zeroret) << 6) | \ + ((cue) << 7) | ((cmpe) << 8) | ((ovfe) << 9) | ((equf) << 10) | ((ovff) << 11)) + +#endif // __SYSDEFS_H__ diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp new file mode 100644 index 0000000000..df16990032 --- /dev/null +++ b/backends/platform/ps2/systemps2.cpp @@ -0,0 +1,798 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include <kernel.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sifrpc.h> +#include <loadfile.h> +#include <malloc.h> +#include <assert.h> +#include <iopcontrol.h> +#include <iopheap.h> +#include "common/scummsys.h" +#include "../intern.h" +#include "base/engine.h" +#include "backends/ps2/systemps2.h" +#include "backends/ps2/Gs2dScreen.h" +#include "backends/ps2/ps2input.h" +#include "backends/ps2/irxboot.h" +#include <sjpcm.h> +#include <libhdd.h> +#include "backends/ps2/savefile.h" +#include "common/file.h" +#include "backends/ps2/sysdefs.h" +#include <libmc.h> +#include <libpad.h> +#include "backends/ps2/cd.h" +#include <sio.h> +#include <fileXio_rpc.h> +#include "backends/ps2/asyncfio.h" +#include "eecodyvdfs.h" +#include "graphics/surface.h" +#include "graphics/font.h" + +// asm("mfc0 %0, $9\n" : "=r"(tickStart)); + +extern void *_gp; + +#define TIMER_STACK_SIZE (1024 * 32) +#define SOUND_STACK_SIZE (1024 * 32) +#define SMP_PER_BLOCK 800 +#define BUS_CLOCK 147456000 // bus clock, a little less than 150 mhz +#define CLK_DIVIS 5760 // the timer IRQ handler gets called (BUS_CLOCK / 256) / CLK_DIVIS times per second (100 times) + +static int g_TimerThreadSema = -1, g_SoundThreadSema = -1; +static int g_MainWaitSema = -1, g_TimerWaitSema = -1; +static volatile int32 g_MainWakeUp = 0, g_TimerWakeUp = 0; +volatile uint32 msecCount = 0; + +OSystem_PS2 *g_systemPs2; + +int gBitFormat = 555; + +#define FOREVER 2147483647 + +namespace Graphics { + extern const NewFont g_sysfont; +}; + +extern AsyncFio fio; + +void sioprintf(const char *zFormat, ...) { + va_list ap; + char resStr[2048]; + + va_start(ap,zFormat); + vsnprintf(resStr, 2048, zFormat, ap); + va_end(ap); + + sio_puts(resStr); +} + +extern "C" int scummvm_main(int argc, char *argv[]); + +extern "C" int main(int argc, char *argv[]) { + SifInitRpc(0); + + ee_thread_t thisThread; + int tid = GetThreadId(); + ReferThreadStatus(tid, &thisThread); + + sioprintf("Thread Start Priority = %d\n", thisThread.current_priority); + if ((thisThread.current_priority < 5) || (thisThread.current_priority > 80)) { + /* Depending on the way ScummVM is run, we may get here with different + thread priorities. + The PS2 BIOS executes it with priority = 0, ps2link uses priority 64. + Don't know about NapLink, etc. + The priority doesn't matter too much, but we need to be at least at prio 3, + so we can have the timer thread run at prio 2 and the sound thread at prio 1 */ + sioprintf("Changing thread priority"); + int res = ChangeThreadPriority(tid, 20); + sioprintf("Result = %d", res); + } + + sioprintf("Creating system"); + g_system = g_systemPs2 = new OSystem_PS2(argv[0]); + + sioprintf("init done. starting ScummVM."); + return scummvm_main(argc, argv); +} + +s32 timerInterruptHandler(s32 cause) { + T0_MODE = 0xDC2; // same value as in initialization. + msecCount += 10; + + iSignalSema(g_SoundThreadSema); + iSignalSema(g_TimerThreadSema); + + if (g_MainWakeUp) { + g_MainWakeUp -= 10; + if (g_MainWakeUp <= 0) { + iSignalSema(g_MainWaitSema); + g_MainWakeUp = 0; + } + } + if (g_TimerWakeUp) { + g_TimerWakeUp -= 10; + if (g_TimerWakeUp <= 0) { + iSignalSema(g_TimerWaitSema); + g_TimerWakeUp = 0; + } + } + return 0; +} + +void systemTimerThread(OSystem_PS2 *system) { + system->timerThread(); +} + +void systemSoundThread(OSystem_PS2 *system) { + system->soundThread(); +} + +void gluePowerOffCallback(void *system) { + ((OSystem_PS2*)system)->powerOffCallback(); +} + +void mass_connect_cb(void *pkt, void *system) { + ((OSystem_PS2*)system)->setUsbMassConnected(true); +} + +void mass_disconnect_cb(void *pkt, void *system) { + ((OSystem_PS2*)system)->setUsbMassConnected(false); +} + +void OSystem_PS2::startIrxModules(int numModules, IrxReference *modules) { + + _usbMassLoaded = _useMouse = _useKbd = _useHdd = false; + + int res = 0, rv = 0; + for (int i = 0; i < numModules; i++) { + if (modules[i].loc == IRX_FILE) { + res = SifLoadModule(modules[i].path, modules[i].argSize, modules[i].args); + sioprintf("Module \"%s\": %d", modules[i].path, res); + if (res < 0) { + msgPrintf(FOREVER, "\"%s\"\nnot found: %d", modules[i].path, res); + delayMillis(5000); + quit(); + } + } else if (modules[i].loc == IRX_BUFFER) { + if (modules[i].errorCode == 0) { + res = SifExecModuleBuffer(modules[i].buffer, modules[i].size, modules[i].argSize, modules[i].args, &rv); + sioprintf("Module \"%s\": EE=%d, IOP=%d", modules[i].path, res, rv); + if ((res >= 0) && (rv >= 0)) { + switch (modules[i].fileRef->purpose) { + case MASS_DRIVER: + _usbMassLoaded = true; + break; + case MOUSE_DRIVER: + _useMouse = true; + break; + case KBD_DRIVER: + _useKbd = true; + break; + case HDD_DRIVER: + _useHdd = true; + break; + default: + break; + } + } + } else + sioprintf("Module \"%s\" wasn't found: %d", modules[i].path, modules[i].errorCode); + + if ((modules[i].errorCode < 0) || (res < 0) || (rv < 0)) { + if (!(modules[i].fileRef->flags & OPTIONAL)) { + if (modules[i].errorCode < 0) + msgPrintf(FOREVER, "\"%s\"\nnot found: %d", modules[i].path, modules[i].errorCode); + else + msgPrintf(FOREVER, "Couldn't start\n\"%s\"\nEE=%d IOP=%d", modules[i].path, res, rv); + delayMillis(5000); + quit(); + } + } + + if (modules[i].buffer); + free(modules[i].buffer); + } else { + sioprintf("module %d of %d damaged, loc %d, path %s", i, numModules, modules[i].loc, modules[i].path); + } + free(modules[i].path); + } + free(modules); + sioprintf("done"); + sioprintf("UsbMass: %sloaded", _usbMassLoaded ? "" : "not "); + sioprintf("Mouse: %sloaded", _useMouse ? "" : "not "); + sioprintf("Kbd: %sloaded", _useKbd ? "" : "not "); + sioprintf("Hdd: %sloaded", _useHdd ? "" : "not "); +} + +OSystem_PS2::OSystem_PS2(const char *elfPath) { + _soundStack = _timerStack = NULL; + _scummTimerProc = NULL; + _scummSoundProc = NULL; + _scummSoundParam = NULL; + _printY = 0; + _msgClearTime = 0; + _systemQuit = false; + _usbMassConnected = false; + + _screen = new Gs2dScreen(320, 200, TV_DONT_CARE); + + sioprintf("Initializing system..."); + initTimer(); + + _screen->wantAnim(true); + + char irxPath[256]; + _bootDevice = detectBootPath(elfPath, irxPath); + + IrxReference *modules; + int numModules = loadIrxModules(_bootDevice, irxPath, &modules); + + if (_bootDevice != HOST) { + sio_puts("Resetting IOP."); + cdvdInit(CDVD_EXIT); + cdvdExit(); + SifExitIopHeap(); + SifLoadFileExit(); + SifExitRpc(); + SifIopReset("rom0:UDNL rom0:EELOADCNF", 0); + while (!SifIopSync()) + ; + sio_puts("IOP synced."); + SifInitRpc(0); + SifLoadFileInit(); + cdvdInit(CDVD_INIT_WAIT); + } + startIrxModules(numModules, modules); + + int res; + if ((res = fileXioInit()) < 0) { + msgPrintf(FOREVER, "FXIO Init failed: %d", res); + quit(); + } + + if ((res = initCdvdFs()) < 0) { + msgPrintf(FOREVER, "CoDyVDfs bind failed: %d", res); + quit(); + } + + if ((res = SjPCM_Init(0)) < 0) { + msgPrintf(FOREVER, "SjPCM Bind failed: %d\n", res); + quit(); + } + + if (_useHdd) { + if ((hddCheckPresent() < 0) || (hddCheckFormatted() < 0)) + _useHdd = false; + + hddPreparePoweroff(); + hddSetUserPoweroffCallback(gluePowerOffCallback, this); + } + + fileXioSetBlockMode(FXIO_NOWAIT); + + _mouseVisible = false; + + sioprintf("reading RTC"); + readRtcTime(); + + if (_useHdd) { + if (fio.mount("pfs0:", "hdd0:+ScummVM", 0) >= 0) + printf("Successfully mounted!\n"); + else + _useHdd = false; + } + + sioprintf("Starting SavefileManager"); + _saveManager = new Ps2SaveFileManager(this, _screen); + + sioprintf("Initializing ps2Input"); + _input = new Ps2Input(this, _useMouse, _useKbd); + + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _mutexSema = CreateSema(&newSema); + for (int i = 0; i < MAX_MUTEXES; i++) { + _mutex[i].sema = -1; + _mutex[i].count = _mutex[i].owner = 0; + } + + _screen->wantAnim(false); + _screen->clearScreen(); +} + +OSystem_PS2::~OSystem_PS2(void) { +} + +void OSystem_PS2::initTimer(void) { + // first setup the two threads that get activated by the timer: + // the timerthread and the soundthread + ee_sema_t threadSema; + threadSema.init_count = 0; + threadSema.max_count = 255; + g_TimerThreadSema = CreateSema(&threadSema); + g_SoundThreadSema = CreateSema(&threadSema); + assert((g_TimerThreadSema >= 0) && (g_SoundThreadSema >= 0)); + + ee_thread_t timerThread, soundThread, thisThread; + ReferThreadStatus(GetThreadId(), &thisThread); + + _timerStack = (uint8*)malloc(TIMER_STACK_SIZE); + _soundStack = (uint8*)malloc(SOUND_STACK_SIZE); + + // give timer thread a higher priority than main thread + timerThread.initial_priority = thisThread.current_priority - 1; + timerThread.stack = _timerStack; + timerThread.stack_size = TIMER_STACK_SIZE; + timerThread.func = (void *)systemTimerThread; + timerThread.gp_reg = &_gp; + + // soundthread's priority is higher than main- and timerthread + soundThread.initial_priority = thisThread.current_priority - 2; + soundThread.stack = _soundStack; + soundThread.stack_size = SOUND_STACK_SIZE; + soundThread.func = (void *)systemSoundThread; + soundThread.gp_reg = &_gp; + + _timerTid = CreateThread(&timerThread); + _soundTid = CreateThread(&soundThread); + + assert((_timerTid >= 0) && (_soundTid >= 0)); + + StartThread(_timerTid, this); + StartThread(_soundTid, this); + + // these semaphores are used for OSystem::delayMillis() + threadSema.init_count = 0; + threadSema.max_count = 1; + g_MainWaitSema = CreateSema(&threadSema); + g_TimerWaitSema = CreateSema(&threadSema); + assert((g_MainWaitSema >= 0) && (g_TimerWaitSema >= 0)); + + // threads done, start the interrupt handler + _intrId = AddIntcHandler( INT_TIMER0, timerInterruptHandler, 0); // 0=first handler + assert(_intrId >= 0); + EnableIntc(INT_TIMER0); + T0_HOLD = 0; + T0_COUNT = 0; + T0_COMP = CLK_DIVIS; // (BUS_CLOCK / 256) / CLK_DIVIS = 100 + T0_MODE = TIMER_MODE( 2, 0, 0, 0, 1, 1, 1, 0, 1, 1); + + DI(); + SifAddCmdHandler(0x12, mass_connect_cb, this); + SifAddCmdHandler(0x13, mass_disconnect_cb, this); + EI(); +} + +void OSystem_PS2::timerThread(void) { + while (!_systemQuit) { + WaitSema(g_TimerThreadSema); + if (_scummTimerProc) + _scummTimerProc(0); + } + ExitThread(); +} + +void OSystem_PS2::soundThread(void) { + ee_sema_t soundSema; + soundSema.init_count = 1; + soundSema.max_count = 1; + _soundSema = CreateSema(&soundSema); + assert(_soundSema >= 0); + int16 *soundBufL = (int16*)memalign(64, SMP_PER_BLOCK * sizeof(int16) * 2); + int16 *soundBufR = soundBufL + SMP_PER_BLOCK; + + int bufferedSamples = 0; + int cycles = 0; + + while (!_systemQuit) { + WaitSema(g_SoundThreadSema); + + if (!(cycles & 31)) + bufferedSamples = SjPCM_Buffered(); + else + bufferedSamples -= 480; + cycles++; + + WaitSema(_soundSema); + if (_scummSoundProc) { + if (bufferedSamples <= 8 * SMP_PER_BLOCK) { + // we have to produce more samples, call sound mixer + // the scratchpad at 0x70000000 is used as temporary soundbuffer + _scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + + // demux data into 2 buffers, L and R + __asm__ ( + "move $t2, %1\n\t" // dest buffer right + "move $t3, %0\n\t" // dest buffer left + "lui $t8, 0x7000\n\t" // muxed buffer, fixed at 0x70000000 + "addiu $t9, $0, 100\n\t" // number of loops + "mtsab $0, 2\n\t" // set qword shift = 2 byte + + "loop:\n\t" + " lq $t4, 0($t8)\n\t" // load 8 muxed samples + " lq $t5, 16($t8)\n\t" // load 8 more muxed samples + + " qfsrv $t6, $0, $t4\n\t" // shift right for second + " qfsrv $t7, $0, $t5\n\t" // packing step (right channel) + + " ppach $t4, $t5, $t4\n\t" // combine left channel data + " ppach $t6, $t7, $t6\n\t" // right channel data + + " sq $t4, 0($t3)\n\t" // write back + " sq $t6, 0($t2)\n\t" // + + " addiu $t9, -1\n\t" // decrement loop counter + " addiu $t2, 16\n\t" // increment pointers + " addiu $t3, 16\n\t" + " addiu $t8, 32\n\t" + " bnez $t9, loop\n\t" // loop + : // outputs + : "r"(soundBufL), "r"(soundBufR) // inputs + // : "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "$t9" // destroyed + : "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25" // destroyed + ); + // and feed it into the SPU + // non-blocking call, the function will return before the buffer's content + // was transferred. + SjPCM_Enqueue((short int*)soundBufL, (short int*)soundBufR, SMP_PER_BLOCK, 0); + bufferedSamples += SMP_PER_BLOCK; + } + } + SignalSema(_soundSema); + } + free(soundBufL); + DeleteSema(_soundSema); + ExitThread(); +} + +bool OSystem_PS2::hddPresent(void) { + return _useHdd; +} + +void OSystem_PS2::setUsbMassConnected(bool stat) { + _usbMassConnected = stat; +} + +bool OSystem_PS2::usbMassPresent(void) { + return _usbMassConnected; +} + +void OSystem_PS2::initSize(uint width, uint height) { + printf("initializing new size: (%d/%d)...", width, height); + _screen->newScreenSize(width, height); + _screen->setMouseXy(width / 2, height / 2); + _input->newRange(0, 0, width - 1, height - 1); + _input->warpTo(width / 2, height / 2); + + _oldMouseX = width / 2; + _oldMouseY = height / 2; + printf("done\n"); +} + +void OSystem_PS2::setPalette(const byte *colors, uint start, uint num) { + _screen->setPalette((const uint32*)colors, (uint8)start, (uint16)num); +} + +void OSystem_PS2::grabPalette(byte *colors, uint start, uint num) { + _screen->grabPalette((uint32*)colors, (uint8)start, (uint16)num); +} + +void OSystem_PS2::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { + _screen->copyScreenRect((const uint8*)buf, pitch, x, y, w, h); +} + +bool OSystem_PS2::grabRawScreen(Graphics::Surface *surf) { + _screen->grabScreen(surf); + return true; +} + +void OSystem_PS2::updateScreen(void) { + if (_msgClearTime && (_msgClearTime < getMillis())) { + _screen->clearPrintfOverlay(); + _msgClearTime = 0; + } + _screen->updateScreen(); +} + +uint32 OSystem_PS2::getMillis(void) { + return msecCount; +} + +void OSystem_PS2::delayMillis(uint msecs) { + if (msecs == 0) + return; + + int tid = GetThreadId(); + if (tid == _soundTid) { + sioprintf("ERROR: delayMillis() from sound thread!"); + return; + } + + if (tid == _timerTid) { + g_TimerWakeUp = (int32)msecs; + WaitSema(g_TimerWaitSema); + } else { + g_MainWakeUp = (int32)msecs; + WaitSema(g_MainWaitSema); + } +} + +void OSystem_PS2::setTimerCallback(OSystem::TimerProc callback, int interval) { + if (callback && (interval != 10)) + sioprintf("unhandled timer interval: %d\n", interval); + _scummTimerProc = callback; +} + +int OSystem_PS2::getOutputSampleRate(void) const { + return 48000; +} + +bool OSystem_PS2::setSoundCallback(SoundProc proc, void *param) { + assert(proc != NULL); + + WaitSema(_soundSema); + _scummSoundProc = proc; + _scummSoundParam = param; + SignalSema(_soundSema); + return true; +} + +void OSystem_PS2::clearSoundCallback(void) { + WaitSema(_soundSema); + _scummSoundProc = NULL; + _scummSoundParam = NULL; + SignalSema(_soundSema); +} + +Common::SaveFileManager *OSystem_PS2::getSavefileManager(void) { + return _saveManager; +} + +void OSystem_PS2::setShakePos(int shakeOffset) { + _screen->setShakePos(shakeOffset); +} + +bool OSystem_PS2::showMouse(bool visible) { + bool retVal = _mouseVisible; + _screen->showMouse(visible); + _mouseVisible = visible; + return retVal; +} + +void OSystem_PS2::warpMouse(int x, int y) { + _input->warpTo((uint16)x, (uint16)y); + _screen->setMouseXy(x, y); +} + +void OSystem_PS2::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { + _screen->setMouseOverlay(buf, w, h, hotspot_x, hotspot_y, keycolor); +} + +bool OSystem_PS2::openCD(int drive) { + return false; +} + +bool OSystem_PS2::pollCD(void) { + return false; +} + +void OSystem_PS2::playCD(int track, int num_loops, int start_frame, int duration) { +} + +void OSystem_PS2::stopCD(void) { +} + +void OSystem_PS2::updateCD(void) { +} + +void OSystem_PS2::showOverlay(void) { + _screen->showOverlay(); +} + +void OSystem_PS2::hideOverlay(void) { + _screen->hideOverlay(); +} + +void OSystem_PS2::clearOverlay(void) { + _screen->clearOverlay(); +} + +void OSystem_PS2::grabOverlay(OverlayColor *buf, int pitch) { + _screen->grabOverlay((uint16*)buf, (uint16)pitch); +} + +void OSystem_PS2::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { + _screen->copyOverlayRect((uint16*)buf, (uint16)pitch, (uint16)x, (uint16)y, (uint16)w, (uint16)h); +} + +const OSystem::GraphicsMode OSystem_PS2::_graphicsMode = { NULL, NULL, 0 }; + +const OSystem::GraphicsMode *OSystem_PS2::getSupportedGraphicsModes(void) const { + return &_graphicsMode; +} + +bool OSystem_PS2::setGraphicsMode(int mode) { + return (mode == 0); +} + +int OSystem_PS2::getGraphicsMode(void) const { + return 0; +} + +int OSystem_PS2::getDefaultGraphicsMode(void) const { + return 0; +} + +bool OSystem_PS2::pollEvent(Event &event) { + bool res = _input->pollEvent(&event); + if (res && (event.type == EVENT_MOUSEMOVE)) + _screen->setMouseXy(event.mouse.x, event.mouse.y); + return res; +} + +OverlayColor OSystem_PS2::RGBToColor(uint8 r, uint8 g, uint8 b) { + return (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10); +} + +void OSystem_PS2::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { + r = (color & 0x1F) << 3; + g = ((color >> 5) & 0x1F) << 3; + b = ((color >> 10) & 0x1F) << 3; +} + +int16 OSystem_PS2::getHeight(void) { + return _screen->getHeight(); +} + +int16 OSystem_PS2::getWidth(void) { + return _screen->getWidth(); +} + +void OSystem_PS2::msgPrintf(int millis, char *format, ...) { + va_list ap; + char resStr[1024]; + memset(resStr, 0, 1024); + + va_start(ap, format); + vsnprintf(resStr, 1023, format, ap); + va_end(ap); + + uint16 posY = 2; + int maxWidth = 0; + + Graphics::Surface surf; + surf.create(300, 200, 1); + + char *lnSta = resStr; + while (*lnSta && (posY < 180)) { + char *lnEnd = lnSta; + while ((*lnEnd) && (*lnEnd != '\n')) + lnEnd++; + *lnEnd = '\0'; + + Common::String str(lnSta); + int width = Graphics::g_sysfont.getStringWidth(str); + if (width > maxWidth) + maxWidth = width; + int posX = (300 - width) / 2; + Graphics::g_sysfont.drawString(&surf, str, posX, posY, 300 - posX, 1); + posY += 14; + + lnSta = lnEnd + 1; + } + + uint8 *scrBuf = (uint8*)memalign(64, 320 * 200); + memset(scrBuf, 4, 320 * 200); + + uint8 *dstPos = scrBuf + ((200 - posY) >> 1) * 320 + (320 - maxWidth) / 2; + for (int y = 0; y < posY; y++) { + uint8 *srcPos = (uint8*)surf.getBasePtr((300 - maxWidth) / 2, y); + for (int x = 0; x < maxWidth; x++) + dstPos[x] = srcPos[x] + 5; + dstPos += 320; + } + surf.free(); + _screen->copyPrintfOverlay(scrBuf); + free(scrBuf); + _msgClearTime = millis + getMillis(); +} + +void OSystem_PS2::powerOffCallback(void) { + sioprintf("powerOffCallback"); + _saveManager->quit(); + if (_useHdd) { + sioprintf("umount"); + fio.umount("pfs0:"); + } + sioprintf("fxio"); + // enable blocking FXIO so libhdd will correctly close drive, etc. + fileXioSetBlockMode(FXIO_WAIT); + sioprintf("done"); +} + +void OSystem_PS2::quit(void) { + if (_bootDevice == HOST) { + printf("OSystem_PS2::quit\n"); + SleepThread(); + } else { + sioprintf("OSystem_PS2::quit"); + if (_useHdd) { + driveStandby(); + fio.umount("pfs0:"); + } + clearSoundCallback(); + setTimerCallback(NULL, 0); + _screen->wantAnim(false); + _systemQuit = true; + ee_thread_t statSound, statTimer; + do { // wait until both threads called ExitThread() + ReferThreadStatus(_timerTid, &statTimer); + ReferThreadStatus(_soundTid, &statSound); + } while ((statSound.status != 0x10) || (statTimer.status != 0x10)); + DeleteThread(_timerTid); + DeleteThread(_soundTid); + free(_timerStack); + free(_soundStack); + DisableIntc(INT_TIMER0); + RemoveIntcHandler(INT_TIMER0, _intrId); + + _saveManager->quit(); + _screen->quit(); + + padEnd(); // stop pad library + cdvdInit(CDVD_EXIT); + sioprintf("resetting iop"); + SifIopReset(NULL, 0); + SifExitRpc(); + while (!SifIopSync()); + SifInitRpc(0); + cdvdExit(); + SifExitRpc(); + FlushCache(0); + SifLoadFileExit(); + sioprintf("Restarting ScummVM"); + LoadExecPS2("cdrom0:\\SCUMMVM.ELF", 0, NULL); // resets the console and executes the ELF + } +} + +void OSystem_PS2::makeConfigPath(char *dest) { + FILE *handle; + strcpy(dest, "cdfs:/ScummVM.ini"); + handle = ps2_fopen(dest, "r"); + if (_usbMassConnected && !handle) { + strcpy(dest, "mass:/ScummVM.ini"); + handle = ps2_fopen(dest, "r"); + } + if (handle) + ps2_fclose(handle); + else + strcpy(dest, "mc0:ScummVM/scummvm.ini"); +} + + diff --git a/backends/platform/ps2/systemps2.h b/backends/platform/ps2/systemps2.h new file mode 100644 index 0000000000..4c51e78c66 --- /dev/null +++ b/backends/platform/ps2/systemps2.h @@ -0,0 +1,148 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SYSTEMPS2_H +#define SYSTEMPS2_H + +#include "common/stdafx.h" +#include "common/system.h" + +class Gs2dScreen; +class Ps2Input; +class Ps2SaveFileManager; +struct IrxReference; + +extern void sioprintf(const char *zFormat, ...); + +#define MAX_MUTEXES 16 + +struct Ps2Mutex { + int sema; + int owner; + int count; +}; + +class OSystem_PS2 : public OSystem { +public: + OSystem_PS2(const char *elfPath); + virtual ~OSystem_PS2(void); + virtual void initSize(uint width, uint height); + + virtual int16 getHeight(void); + virtual int16 getWidth(void); + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void setShakePos(int shakeOffset); + virtual void grabPalette(byte *colors, uint start, uint num); + virtual bool grabRawScreen(Graphics::Surface *surf); + virtual void updateScreen(); + + 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 bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale = 1); + + virtual uint32 getMillis(); + virtual void delayMillis(uint msecs); + virtual void setTimerCallback(TimerProc callback, int interval); + virtual bool pollEvent(Event &event); + + virtual bool setSoundCallback(SoundProc proc, void *param); + virtual void clearSoundCallback(); + virtual int getOutputSampleRate(void) 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 MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + + virtual void quit(); + + virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); + + virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); + + virtual Common::SaveFileManager *getSavefileManager(); + + void timerThread(void); + void soundThread(void); + void msgPrintf(int millis, char *format, ...); + void makeConfigPath(char *dest); + + void powerOffCallback(void); + bool hddPresent(void); + bool usbMassPresent(void); + void setUsbMassConnected(bool stat); + +private: + void startIrxModules(int numModules, IrxReference *modules); + + volatile OSystem::TimerProc _scummTimerProc; + volatile OSystem::SoundProc _scummSoundProc; + void *_scummSoundParam; + int _soundSema; + + void initTimer(void); + void readRtcTime(void); + + bool _mouseVisible; + bool _useMouse, _useKbd, _useHdd, _usbMassLoaded, _usbMassConnected; + + Ps2SaveFileManager *_saveManager; + + Gs2dScreen *_screen; + Ps2Input *_input; + uint16 _oldMouseX, _oldMouseY; + uint32 _msgClearTime; + uint16 _printY; + + int _mutexSema; + Ps2Mutex _mutex[MAX_MUTEXES]; + + uint8 *_timerStack, *_soundStack; + int _timerTid, _soundTid; + int _intrId; + volatile bool _systemQuit; + static const GraphicsMode _graphicsMode; + + int _bootDevice; +}; + +#endif // SYSTEMPS2_H + |