/* Copyright 2003 Guillaume Duhamel Copyright 2004-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "cs2.h" #include "debug.h" #include "error.h" #include "netlink.h" #include "scsp.h" #include "scu.h" #include "smpc.h" #include "yui.h" #define CDB_HIRQ_CMOK 0x0001 #define CDB_HIRQ_DRDY 0x0002 #define CDB_HIRQ_CSCT 0x0004 #define CDB_HIRQ_BFUL 0x0008 #define CDB_HIRQ_PEND 0x0010 #define CDB_HIRQ_DCHG 0x0020 #define CDB_HIRQ_ESEL 0x0040 #define CDB_HIRQ_EHST 0x0080 #define CDB_HIRQ_ECPY 0x0100 #define CDB_HIRQ_EFLS 0x0200 #define CDB_HIRQ_SCDQ 0x0400 #define CDB_HIRQ_MPED 0x0800 #define CDB_HIRQ_MPCM 0x1000 #define CDB_HIRQ_MPST 0x2000 #define CDB_STAT_BUSY 0x00 #define CDB_STAT_PAUSE 0x01 #define CDB_STAT_STANDBY 0x02 #define CDB_STAT_PLAY 0x03 #define CDB_STAT_SEEK 0x04 #define CDB_STAT_SCAN 0x05 #define CDB_STAT_OPEN 0x06 #define CDB_STAT_NODISC 0x07 #define CDB_STAT_RETRY 0x08 #define CDB_STAT_ERROR 0x09 #define CDB_STAT_FATAL 0x0A #define CDB_STAT_PERI 0x20 #define CDB_STAT_TRNS 0x40 #define CDB_STAT_WAIT 0x80 #define CDB_STAT_REJECT 0xFF #define CDB_PLAYTYPE_SECTOR 0x01 #define CDB_PLAYTYPE_FILE 0x02 Cs2 * Cs2Area = NULL; ip_struct *cdip = NULL; extern CDInterface *CDCoreList[]; ////////////////////////////////////////////////////////////////////////////// static INLINE void doCDReport(u8 status) { Cs2Area->reg.CR1 = (status << 8) | ((Cs2Area->options & 0xF) << 4) | (Cs2Area->repcnt & 0xF); Cs2Area->reg.CR2 = (Cs2Area->ctrladdr << 8) | Cs2Area->track; Cs2Area->reg.CR3 = (u16)((Cs2Area->index << 8) | ((Cs2Area->FAD >> 16) & 0xFF)); Cs2Area->reg.CR4 = (u16) Cs2Area->FAD; } ////////////////////////////////////////////////////////////////////////////// static INLINE void doMPEGReport(u8 status) { Cs2Area->reg.CR1 = (status << 8) | Cs2Area->actionstatus; Cs2Area->reg.CR2 = Cs2Area->vcounter; Cs2Area->reg.CR3 = (Cs2Area->pictureinfo << 8) | Cs2Area->mpegaudiostatus; Cs2Area->reg.CR4 = Cs2Area->mpegvideostatus; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Cs2ReadByte(u32 addr) { addr &= 0xFFFFF; // fix me(I should really have proper mapping) if(Cs2Area->carttype == CART_NETLINK) return NetlinkReadByte(addr); else { // only netlink seems to use byte-access switch (addr) { case 0x95001: case 0x95005: case 0x95009: case 0x9500D: case 0x95011: case 0x95015: case 0x95019: case 0x9501D: return 0xFF; default: break; } } LOG("Unimplemented cs2 byte read: %08X\n", addr); return 0xFF; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteByte(u32 addr, u8 val) { addr &= 0xFFFFF; // fix me(I should really have proper mapping) if(Cs2Area->carttype == CART_NETLINK) { NetlinkWriteByte(addr, val); return; } else { // only netlink seems to use byte-access switch (addr) { case 0x2503D: case 0x95011: case 0x9501D: return; default: break; } } LOG("Unimplemented cs2 byte write: %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Cs2ReadWord(u32 addr) { u16 val = 0; addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: case 0x9000A: val = Cs2Area->reg.HIRQ; if (Cs2Area->isbufferfull) val |= CDB_HIRQ_BFUL; else val &= ~CDB_HIRQ_BFUL; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; if (Cs2Area->isonesectorstored) val |= CDB_HIRQ_CSCT; else val &= ~CDB_HIRQ_CSCT; Cs2Area->reg.HIRQ = val; // CDLOG("cs2\t: Hirq read, Hirq mask = %x - ret: %x\n", Memory::getWord(0x9000C), val); return val; case 0x9000C: case 0x9000E: return Cs2Area->reg.HIRQMASK; case 0x90018: case 0x9001A: return Cs2Area->reg.CR1; case 0x9001C: case 0x9001E: return Cs2Area->reg.CR2; case 0x90020: case 0x90022: return Cs2Area->reg.CR3; case 0x90024: case 0x90026: Cs2Area->_command = 0; return Cs2Area->reg.CR4; case 0x90028: case 0x9002A: return Cs2Area->reg.MPEGRGB; case 0x98000: // transfer info switch (Cs2Area->infotranstype) { case 0: // Get Toc Data if (Cs2Area->transfercount % 4 == 0) val = (u16)((Cs2Area->TOC[Cs2Area->transfercount >> 2] & 0xFFFF0000) >> 16); else val = (u16)Cs2Area->TOC[Cs2Area->transfercount >> 2]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (0xCC * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 1: // Get File Info(1 file info) val = (Cs2Area->transfileinfo[Cs2Area->transfercount] << 8) | Cs2Area->transfileinfo[Cs2Area->transfercount + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (0x6 * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 2: // Get File Info(254 file info) // Do we need to retrieve the next file info? if (Cs2Area->transfercount % (0x6 * 2) == 0) { // yes we do Cs2SetupFileInfoTransfer(2 + (Cs2Area->transfercount / (0x6 * 2))); } val = (Cs2Area->transfileinfo[Cs2Area->transfercount % (0x6 * 2)] << 8) | Cs2Area->transfileinfo[Cs2Area->transfercount % (0x6 * 2) + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (254 * (0x6 * 2))) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; default: break; } break; default: LOG("cs2\t: Undocumented register read %08X\n", addr); // val = T3ReadWord(Cs2Area->mem, addr); break; } return val; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteWord(u32 addr, u16 val) { addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: case 0x9000A: Cs2Area->reg.HIRQ &= val; return; case 0x9000C: case 0x9000E: Cs2Area->reg.HIRQMASK = val; return; case 0x90018: case 0x9001A: Cs2Area->status &= ~CDB_STAT_PERI; Cs2Area->_command = 1; Cs2Area->reg.CR1 = val; return; case 0x9001C: case 0x9001E: Cs2Area->reg.CR2 = val; return; case 0x90020: case 0x90022: Cs2Area->reg.CR3 = val; return; case 0x90024: case 0x90026: Cs2Area->reg.CR4 = val; Cs2SetCommandTiming(Cs2Area->reg.CR1 >> 8); return; case 0x90028: case 0x9002A: Cs2Area->reg.MPEGRGB = val; return; default: LOG("cs2\t:Undocumented register write %08X\n", addr); // T3WriteWord(Cs2Area->mem, addr, val); break; } } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Cs2ReadLong(u32 addr) { s32 i; u32 val = 0; addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: val = Cs2Area->reg.HIRQ; if (Cs2Area->isbufferfull) val |= CDB_HIRQ_BFUL; else val &= ~CDB_HIRQ_BFUL; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; if (Cs2Area->isonesectorstored) val |= CDB_HIRQ_CSCT; else val &= ~CDB_HIRQ_CSCT; Cs2Area->reg.HIRQ = (u16)val; val |= (val << 16); return val; case 0x9000C: return ((Cs2Area->reg.HIRQMASK << 16) | Cs2Area->reg.HIRQMASK); case 0x90018: return ((Cs2Area->reg.CR1 << 16) | Cs2Area->reg.CR1); case 0x9001C: return ((Cs2Area->reg.CR2 << 16) | Cs2Area->reg.CR2); case 0x90020: return ((Cs2Area->reg.CR3 << 16) | Cs2Area->reg.CR3); case 0x90024: Cs2Area->_command = 0; return ((Cs2Area->reg.CR4 << 16) | Cs2Area->reg.CR4); case 0x90028: return ((Cs2Area->reg.MPEGRGB << 16) | Cs2Area->reg.MPEGRGB); case 0x18000: // transfer data if (Cs2Area->datatranstype != -1) { // get sector // Make sure we still have sectors to transfer if (Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { // Transfer Data const u8 *ptr = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; #ifdef WORDS_BIGENDIAN val = *((const u32 *) ptr); #else val = BSWAP32(*((const u32 *) ptr)); #endif // increment datatransoffset/cdwnum Cs2Area->cdwnum += 4; Cs2Area->datatransoffset += 4; // Make sure we're not beyond the sector size boundry if (Cs2Area->datatransoffset >= Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } else { if (Cs2Area->datatranstype == 2) { // Ok, so we don't have any more sectors to // transfer, might as well delete them all. Cs2Area->datatranstype = -1; // free blocks for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } } break; default: LOG("cs2\t: Undocumented register read %08X\n", addr); // val = T3ReadLong(Cs2Area->mem, addr); break; } return val; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteLong(UNUSED u32 addr, UNUSED u32 val) { LOG("cs2\t: Long writing isn't implemented\n"); // T3WriteLong(Cs2Area->mem, addr, val); } ////////////////////////////////////////////////////////////////////////////// /* Copy "count" 32-bit words from the CD buffer to type-1 memory "dest" (a * native pointer), as though 0x25818000 had been read that many times */ void FASTCALL Cs2RapidCopyT1(void *dest, u32 count) { u8 *dest8 = (u8 *) dest; if (Cs2Area->datatranstype != -1) { // Copy as many sectors as we have left, one sector at a time while (count > 0 && Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { const u8 *src = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; const u32 size = Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size; const u32 max = size - Cs2Area->datatransoffset; const u32 copy = (max < count*4) ? max : count*4; memcpy(dest8, src, copy); dest8 += copy; count -= copy/4; Cs2Area->datatransoffset += copy; Cs2Area->cdwnum += copy; // Update the sector index if we reached the end of the sector if (Cs2Area->datatransoffset >= size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } // If we're in delete mode and we read through everything in memory, // delete the sectors if (Cs2Area->datatranstype == 2 && Cs2Area->datanumsecttrans >= Cs2Area->datasectstotrans) { u32 i; Cs2Area->datatranstype = -1; for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } if (count > 0) { // We tried to copy more data than was stored, so fill the rest of // the buffer with dummy data memset(dest8, 0xCD, count*4); } } ////////////////////////////////////////////////////////////////////////////// /* Copy "count" 32-bit words from the CD buffer to type-2 memory "dest" (a * native pointer), as though 0x25818000 had been read that many times */ void FASTCALL Cs2RapidCopyT2(void *dest, u32 count) { u32 *dest32 = (u32 *) dest; if (Cs2Area->datatranstype != -1) { // Copy as many sectors as we have left, one sector at a time; copy // four words at a time where possible to improve data parallelism while (count > 0 && Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { const u8 *src = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; const u32 size = Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size; const u32 max = size - Cs2Area->datatransoffset; const u32 copy = (max < count*4) ? max : count*4; u32 i = 0; if (copy >= 16) { for (; i < copy-12; i += 16, src += 16, dest32 += 4) { u32 word0, word1, word2, word3; #ifdef WORDS_BIGENDIAN word0 = ((u32 *)src)[0]; word1 = ((u32 *)src)[1]; word2 = ((u32 *)src)[2]; word3 = ((u32 *)src)[3]; #else word0 = BSWAP16(((u32 *)src)[0]); word1 = BSWAP16(((u32 *)src)[1]); word2 = BSWAP16(((u32 *)src)[2]); word3 = BSWAP16(((u32 *)src)[3]); #endif dest32[0] = word0; dest32[1] = word1; dest32[2] = word2; dest32[3] = word3; } } for (; i < copy; i += 4, src += 4, dest32++) { #ifdef WORDS_BIGENDIAN *dest32 = *(u32 *)src; #else *dest32 = BSWAP16(*(u32 *)src); #endif } count -= copy/4; Cs2Area->datatransoffset += copy; Cs2Area->cdwnum += copy; if (Cs2Area->datatransoffset >= size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } if (Cs2Area->datatranstype == 2 && Cs2Area->datanumsecttrans >= Cs2Area->datasectstotrans) { u32 i; Cs2Area->datatranstype = -1; for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } if (count > 0) { memset(dest32, 0xCD, count*4); } } ////////////////////////////////////////////////////////////////////////////// int Cs2Init(int carttype, int coreid, const char *cdpath, const char *mpegpath, const char *netlinksetting) { int ret; if ((Cs2Area = (Cs2 *) malloc(sizeof(Cs2))) == NULL) return -1; memset(Cs2Area, 0, sizeof(*Cs2Area)); Cs2Area->carttype = carttype; Cs2Area->mpegpath = mpegpath; Cs2Area->cdi=NULL; if ((ret = Cs2ChangeCDCore(coreid, cdpath)) != 0) return ret; Cs2Reset(); // If Modem is connected, set the registers if(Cs2Area->carttype == CART_NETLINK) { if ((ret = NetlinkInit(netlinksetting)) != 0) return ret; } if ((cdip = (ip_struct *) calloc(sizeof(ip_struct), 1)) == NULL) return -1; return 0; } ////////////////////////////////////////////////////////////////////////////// int Cs2ChangeCDCore(int coreid, const char *cdpath) { int i; // Make sure the old core is freed if (Cs2Area->cdi != NULL) Cs2Area->cdi->DeInit(); // So which core do we want? if (coreid == CDCORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; CDCoreList[i] != NULL; i++) { if (CDCoreList[i]->id == coreid) { // Set to current core Cs2Area->cdi = CDCoreList[i]; break; } } if (Cs2Area->cdi == NULL) { Cs2Area->cdi = &DummyCD; return -1; } if (Cs2Area->cdi->Init(cdpath) != 0) { // This might be helpful. YabSetError(YAB_ERR_CANNOTINIT, (void *)Cs2Area->cdi->Name); // Since it failed, instead of it being fatal, we'll just use the dummy // core instead Cs2Area->cdi = &DummyCD; } Cs2Area->isdiskchanged = 1; Cs2Area->status = CDB_STAT_PAUSE; SmpcRecheckRegion(); return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2DeInit(void) { if(Cs2Area != NULL) { if (Cs2Area->cdi != NULL) { Cs2Area->cdi->DeInit(); } if(Cs2Area->carttype == CART_NETLINK) NetlinkDeInit(); free(Cs2Area); } Cs2Area = NULL; if (cdip) free(cdip); cdip = NULL; } ////////////////////////////////////////////////////////////////////////////// void Cs2Reset(void) { u32 i, i2; switch (Cs2Area->cdi->GetStatus()) { case 0: case 1: Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->FAD = 150; Cs2Area->options = 0; Cs2Area->repcnt = 0; Cs2Area->ctrladdr = 0x41; Cs2Area->track = 1; Cs2Area->index = 1; break; case 2: Cs2Area->status = CDB_STAT_NODISC; Cs2Area->FAD = 0xFFFFFFFF; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; break; case 3: Cs2Area->status = CDB_STAT_OPEN; Cs2Area->FAD = 0xFFFFFFFF; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; break; default: break; } Cs2Area->infotranstype = -1; Cs2Area->datatranstype = -1; Cs2Area->transfercount = 0; Cs2Area->cdwnum = 0; Cs2Area->getsectsize = Cs2Area->putsectsize = 2048; Cs2Area->isdiskchanged = 1; Cs2Area->isbufferfull = 0; Cs2Area->isonesectorstored = 0; Cs2Area->isaudio = 0; Cs2Area->reg.CR1 = ( 0 <<8) | 'C'; Cs2Area->reg.CR2 = ('D'<<8) | 'B'; Cs2Area->reg.CR3 = ('L'<<8) | 'O'; Cs2Area->reg.CR4 = ('C'<<8) | 'K'; Cs2Area->reg.HIRQ = 0xFFFF; Cs2Area->reg.HIRQMASK = 0xFFFF; Cs2Area->playFAD = 0xFFFFFFFF; Cs2Area->playendFAD = 0xFFFFFFFF; Cs2Area->playtype = 0; Cs2Area->maxrepeat = 0; // set authentication variables to 0(not authenticated) Cs2Area->satauth = 0; Cs2Area->mpgauth = 0; // clear filter conditions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->filter[i].FAD = 0; Cs2Area->filter[i].range = 0xFFFFFFFF; Cs2Area->filter[i].mode = 0; Cs2Area->filter[i].chan = 0; Cs2Area->filter[i].smmask = 0; Cs2Area->filter[i].cimask = 0; Cs2Area->filter[i].fid = 0; Cs2Area->filter[i].smval = 0; Cs2Area->filter[i].cival = 0; Cs2Area->filter[i].condtrue = 0; Cs2Area->filter[i].condfalse = 0xFF; } // clear partitions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->partition[i].size = -1; Cs2Area->partition[i].numblocks = 0; for (i2 = 0; i2 < MAX_BLOCKS; i2++) { Cs2Area->partition[i].block[i2] = NULL; Cs2Area->partition[i].blocknum[i2] = 0xFF; } } // clear blocks for (i = 0; i < MAX_BLOCKS; i++) { Cs2Area->block[i].size = -1; memset(Cs2Area->block[i].data, 0, 2352); } Cs2Area->blockfreespace = 200; // initialize TOC memset(Cs2Area->TOC, 0xFF, sizeof(Cs2Area->TOC)); // clear filesystem stuff Cs2Area->curdirsect = 0; Cs2Area->curdirsize = 0; Cs2Area->curdirfidoffset = 0; memset(&Cs2Area->fileinfo, 0, sizeof(Cs2Area->fileinfo)); Cs2Area->numfiles = 0; Cs2Area->lastbuffer = 0xFF; Cs2Area->_command = 0; Cs2Area->_periodiccycles = 0; Cs2Area->_commandtiming = 0; Cs2SetTiming(0); // MPEG specific stuff Cs2Area->mpegcon[0].audcon = Cs2Area->mpegcon[0].vidcon = 0x00; Cs2Area->mpegcon[0].audlay = Cs2Area->mpegcon[0].vidlay = 0x00; Cs2Area->mpegcon[0].audbufdivnum = Cs2Area->mpegcon[0].vidbufdivnum = 0xFF; Cs2Area->mpegcon[1].audcon = Cs2Area->mpegcon[1].vidcon = 0x00; Cs2Area->mpegcon[1].audlay = Cs2Area->mpegcon[1].vidlay = 0x00; Cs2Area->mpegcon[1].audbufdivnum = Cs2Area->mpegcon[1].vidbufdivnum = 0xFF; // should verify the following Cs2Area->mpegstm[0].audstm = Cs2Area->mpegstm[0].vidstm = 0x00; Cs2Area->mpegstm[0].audstmid = Cs2Area->mpegstm[0].vidstmid = 0x00; Cs2Area->mpegstm[0].audchannum = Cs2Area->mpegstm[0].vidchannum = 0x00; Cs2Area->mpegstm[1].audstm = Cs2Area->mpegstm[1].vidstm = 0x00; Cs2Area->mpegstm[1].audstmid = Cs2Area->mpegstm[1].vidstmid = 0x00; Cs2Area->mpegstm[1].audchannum = Cs2Area->mpegstm[1].vidchannum = 0x00; } ////////////////////////////////////////////////////////////////////////////// void Cs2Exec(u32 timing) { Cs2Area->_periodiccycles += timing * 3; if (Cs2Area->_commandtiming > 0) { if (Cs2Area->_commandtiming < timing) { Cs2Execute(); Cs2Area->_commandtiming = 0; } else Cs2Area->_commandtiming -= timing; } if (Cs2Area->_periodiccycles >= Cs2Area->_periodictiming) { Cs2Area->_periodiccycles -= Cs2Area->_periodictiming; // Get Drive's current status and compare with old status // switch(cd->getStatus()) // this shouldn't be called every periodic response switch(0) { case 0: case 1: if ((Cs2Area->status & 0xF) == CDB_STAT_NODISC || (Cs2Area->status & 0xF) == CDB_STAT_OPEN) { Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->isdiskchanged = 1; } break; case 2: // may need to change this if ((Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->status = CDB_STAT_NODISC; break; case 3: // may need to change this if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN) Cs2Area->status = CDB_STAT_OPEN; break; default: break; } switch (Cs2Area->status & 0xF) { case CDB_STAT_PAUSE: { // if (FAD >= playFAD && FAD < playendFAD) // status = CDB_STAT_PLAY; // else break; } case CDB_STAT_PLAY: { partition_struct * playpartition; int ret = Cs2ReadFilteredSector(Cs2Area->FAD, &playpartition); switch (ret) { case 0: // Sector Read OK Cs2Area->FAD++; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); if (playpartition != NULL) { // We can use this sector CDLOG("partition number = %d blocks = %d blockfreespace = %d fad = %x playpartition->size = %x isbufferfull = %x\n", (playpartition - Cs2Area->partition), playpartition->numblocks, Cs2Area->blockfreespace, Cs2Area->FAD, playpartition->size, Cs2Area->isbufferfull); Cs2Area->reg.HIRQ |= CDB_HIRQ_CSCT; Cs2Area->isonesectorstored = 1; if (Cs2Area->FAD >= Cs2Area->playendFAD) { // Make sure we don't have to do a repeat if (Cs2Area->repcnt >= Cs2Area->maxrepeat) { // we're done Cs2Area->status = CDB_STAT_PAUSE; Cs2SetTiming(0); Cs2Area->reg.HIRQ |= CDB_HIRQ_PEND; if (Cs2Area->playtype == CDB_PLAYTYPE_FILE) Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS; CDLOG("PLAY HAS ENDED\n"); } else { Cs2Area->FAD = Cs2Area->playFAD; if (Cs2Area->repcnt < 0xE) Cs2Area->repcnt++; Cs2Area->track = Cs2FADToTrack(Cs2Area->FAD); CDLOG("PLAY HAS REPEATED\n"); } } if (Cs2Area->isbufferfull) { CDLOG("BUFFER IS FULL\n"); // status = CDB_STAT_PAUSE; } } else { CDLOG("Sector filtered out\n"); if (Cs2Area->FAD >= Cs2Area->playendFAD) { // Make sure we don't have to do a repeat if (Cs2Area->repcnt >= Cs2Area->maxrepeat) { // we're done Cs2Area->status = CDB_STAT_PAUSE; Cs2SetTiming(0); Cs2Area->reg.HIRQ |= CDB_HIRQ_PEND; if (Cs2Area->playtype == CDB_PLAYTYPE_FILE) Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS; CDLOG("PLAY HAS ENDED\n"); } else { Cs2Area->FAD = Cs2Area->playFAD; if (Cs2Area->repcnt < 0xE) Cs2Area->repcnt++; Cs2Area->track = Cs2FADToTrack(Cs2Area->FAD); CDLOG("PLAY HAS REPEATED\n"); } } } break; case -1: // Things weren't setup correctly break; case -2: // Do a read retry break; } break; } case CDB_STAT_SEEK: break; case CDB_STAT_SCAN: break; case CDB_STAT_RETRY: break; default: break; } if (Cs2Area->_command) return; Cs2Area->status |= CDB_STAT_PERI; // adjust registers appropriately here(fix me) doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_SCDQ; } if(Cs2Area->carttype == CART_NETLINK) NetlinkExec(timing); } ////////////////////////////////////////////////////////////////////////////// /* Returns the number of (emulated) microseconds before the next sector * will have been completely read in */ int Cs2GetTimeToNextSector(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_PLAY) { return 0; } else { // Round up, since the caller wants to know when it'll be safe to check int time = (Cs2Area->_periodictiming - Cs2Area->_periodiccycles + 2) / 3; return time<0 ? 0 : time; } } ////////////////////////////////////////////////////////////////////////////// void Cs2Command(void) { Cs2Area->_command = 1; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetTiming(int playing) { if (playing) { if (Cs2Area->isaudio || Cs2Area->speed1x == 1) Cs2Area->_periodictiming = 40000; // 13333.333... * 3 else Cs2Area->_periodictiming = 20000; // 6666.666... * 3 } else { Cs2Area->_periodictiming = 50000; // 16666.666... * 3 } } ////////////////////////////////////////////////////////////////////////////// void Cs2SetCommandTiming(u8 cmd) { switch(cmd) { default: Cs2Area->_commandtiming = 1; break; } } ////////////////////////////////////////////////////////////////////////////// void Cs2Execute(void) { u16 instruction = Cs2Area->reg.CR1 >> 8; Cs2Area->reg.HIRQ &= ~CDB_HIRQ_CMOK; switch (instruction) { case 0x00: CDLOG("cs2\t: Command: getStatus\n"); Cs2GetStatus(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x01: CDLOG("cs2\t: Command: getHardwareInfo\n"); Cs2GetHardwareInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x02: CDLOG("cs2\t: Command: getToc\n"); Cs2GetToc(); break; case 0x03: CDLOG("cs2\t: Command: getSessionInfo\n"); Cs2GetSessionInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x04: CDLOG("cs2\t: Command: initializeCDSystem %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2InitializeCDSystem(); break; case 0x06: CDLOG("cs2\t: Command: endDataTransfer %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2EndDataTransfer(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x10: CDLOG("cs2\t: Command: playDisc %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2PlayDisc(); break; case 0x11: CDLOG("cs2\t: Command: seekDisc %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SeekDisc(); break; case 0x20: CDLOG("cs2\t: Command: getSubcodeQRW %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSubcodeQRW(); break; case 0x30: CDLOG("cs2\t: Command: setCDDeviceConnection %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetCDDeviceConnection(); break; case 0x32: CDLOG("cs2\t: Command: getLastBufferDestination %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetLastBufferDestination(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x40: CDLOG("cs2\t: Command: setFilterRange\n"); Cs2SetFilterRange(); break; case 0x42: CDLOG("cs2\t: Command: setFilterSubheaderConditions\n"); Cs2SetFilterSubheaderConditions(); break; case 0x43: CDLOG("cs2\t: Command: getFilterSubheaderConditions\n"); Cs2GetFilterSubheaderConditions(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x44: CDLOG("cs2\t: Command: setFilterMode\n"); Cs2SetFilterMode(); break; case 0x45: CDLOG("cs2\t: Command: getFilterMode\n"); Cs2GetFilterMode(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x46: CDLOG("cs2\t: Command: setFilterConnection\n"); Cs2SetFilterConnection(); break; case 0x48: CDLOG("cs2\t: Command: resetSelector %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ResetSelector(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x50: CDLOG("cs2\t: Command: getBufferSize\n"); Cs2GetBufferSize(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x51: // CDLOG("cs2\t: Command: getSectorNumber %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorNumber(); // CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x52: CDLOG("cs2\t: Command: calculateActualSize %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CalculateActualSize(); break; case 0x53: CDLOG("cs2\t: Command: getActualSize\n"); Cs2GetActualSize(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x54: CDLOG("cs2\t: Command: getSectorInfo %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x60: CDLOG("cs2\t: Command: setSectorLength %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetSectorLength(); break; case 0x61: CDLOG("cs2\t: Command: getSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x62: CDLOG("cs2\t: Command: deleteSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2DeleteSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x63: CDLOG("cs2\t: Command: getThenDeleteSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetThenDeleteSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x64: CDLOG("cs2\t: Command: putSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2PutSectorData(); break; case 0x67: CDLOG("cs2\t: Command: getCopyError\n"); Cs2GetCopyError(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x70: CDLOG("cs2\t: Command: changeDirectory %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ChangeDirectory(); break; case 0x71: CDLOG("cs2\t: Command: readDirectory %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ReadDirectory(); break; case 0x72: CDLOG("cs2\t: Command: getFileSystemScope\n"); Cs2GetFileSystemScope(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x73: CDLOG("cs2\t: Command: getFileInfo %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetFileInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x74: CDLOG("cs2\t: Command: readFile %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ReadFile(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x75: CDLOG("cs2\t: Command: abortFile\n"); Cs2AbortFile(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x90: CDLOG("cs2\t: Command: mpegGetStatus\n"); Cs2MpegGetStatus(); break; case 0x91: CDLOG("cs2\t: Command: mpegGetInterrupt\n"); Cs2MpegGetInterrupt(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x92: CDLOG("cs2\t: Command: mpegSetInterruptMask\n"); Cs2MpegSetInterruptMask(); break; case 0x93: CDLOG("cs2\t: Command: mpegInit\n"); Cs2MpegInit(); break; case 0x94: CDLOG("cs2\t: Command: mpegSetMode\n"); Cs2MpegSetMode(); break; case 0x95: CDLOG("cs2\t: Command: mpegPlay\n"); Cs2MpegPlay(); break; case 0x96: CDLOG("cs2\t: Command: mpegSetDecodingMethod\n"); Cs2MpegSetDecodingMethod(); break; case 0x9A: CDLOG("cs2\t: Command: mpegSetConnection\n"); Cs2MpegSetConnection(); break; case 0x9B: CDLOG("cs2\t: Command: mpegGetConnection\n"); Cs2MpegGetConnection(); break; case 0x9D: CDLOG("cs2\t: Command: mpegSetStream\n"); Cs2MpegSetStream(); break; case 0x9E: CDLOG("cs2\t: Command: mpegGetStream\n"); Cs2MpegGetStream(); break; case 0xA0: CDLOG("cs2\t: Command: mpegDisplay\n"); Cs2MpegDisplay(); break; case 0xA1: CDLOG("cs2\t: Command: mpegSetWindow\n"); Cs2MpegSetWindow(); break; case 0xA2: CDLOG("cs2\t: Command: mpegSetBorderColor\n"); Cs2MpegSetBorderColor(); break; case 0xA3: CDLOG("cs2\t: Command: mpegSetFade\n"); Cs2MpegSetFade(); break; case 0xA4: CDLOG("cs2\t: Command: mpegSetVideoEffects\n"); Cs2MpegSetVideoEffects(); break; case 0xAF: CDLOG("cs2\t: Command: mpegSetLSI\n"); Cs2MpegSetLSI(); break; case 0xE0: CDLOG("cs2\t: Command: cmdE0 %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CmdE0(); break; case 0xE1: CDLOG("cs2\t: Command: cmdE1 %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CmdE1(); break; case 0xE2: CDLOG("cs2\t: Command: cmdE2 %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CmdE2(); break; default: CDLOG("cs2\t: Command %02x not implemented\n", instruction); break; } } ////////////////////////////////////////////////////////////////////////////// void Cs2GetStatus(void) { doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetHardwareInfo(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->isdiskchanged = 0; Cs2Area->reg.CR1 = Cs2Area->status << 8; // hardware flags/CD Version Cs2Area->reg.CR2 = 0x0201; // mpeg card exists // mpeg version, it actually is required(at least by the bios) if (Cs2Area->mpgauth) Cs2Area->reg.CR3 = 0x1; else Cs2Area->reg.CR3 = 0; // drive info/revision Cs2Area->reg.CR4 = 0x0400; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetToc(void) { Cs2Area->cdi->ReadTOC(Cs2Area->TOC); Cs2Area->transfercount = 0; Cs2Area->infotranstype = 0; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0xCC; Cs2Area->reg.CR3 = 0x0; Cs2Area->reg.CR4 = 0x0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; Cs2Area->status = CDB_STAT_PAUSE; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSessionInfo(void) { switch (Cs2Area->reg.CR1 & 0xFF) { case 0: Cs2Area->reg.CR3 = (u16)(0x0100 | ((Cs2Area->TOC[101] & 0xFF0000) >> 16)); Cs2Area->reg.CR4 = (u16)Cs2Area->TOC[101]; break; case 1: Cs2Area->reg.CR3 = 0x0100; // return Session number(high byte)/and first byte of Session lba Cs2Area->reg.CR4 = 0; // lower word of Session lba break; default: Cs2Area->reg.CR3 = 0xFFFF; Cs2Area->reg.CR4 = 0xFFFF; break; } Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2InitializeCDSystem(void) { u16 val = 0; u8 initflag = Cs2Area->reg.CR1 & 0xFF; if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) { Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->FAD = 150; } if (initflag & 0x1) { // Reset CD block software } if (initflag & 0x2) { // Decode RW subcode } if (initflag & 0x4) { // Don't confirm Mode 2 subheader } if (initflag & 0x8) { // Retry reading Form 2 sectors } if (initflag & 0x10) Cs2Area->speed1x = 1; else Cs2Area->speed1x = 0; val = Cs2Area->reg.HIRQ & 0xFFE5; Cs2Area->isbufferfull = 0; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ = val | CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2EndDataTransfer(void) { s32 i; if (Cs2Area->cdwnum) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->cdwnum >> 17) & 0xFF)); Cs2Area->reg.CR2 = (u16)(Cs2Area->cdwnum >> 1); Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } else { Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0xFF; // FIXME Cs2Area->reg.CR2 = 0xFFFF; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } // stop any transfers that may be going(this is still probably wrong), and // set/clear the appropriate flags switch (Cs2Area->datatranstype) { case 0: // Get Sector Data Cs2Area->reg.HIRQ |= CDB_HIRQ_EHST; break; case 2: { // Get Then Delete Sector // Make sure we actually have to free something if (Cs2Area->datatranspartition->size <= 0) break; Cs2Area->datatranstype = -1; // free blocks for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos + Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; if (Cs2Area->blockfreespace == 200) Cs2Area->isonesectorstored = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_EHST; break; } default: break; } Cs2Area->cdwnum = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2PlayDisc(void) { u32 pdspos; u32 pdepos; u32 pdpmode; // Get all the arguments pdspos = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; pdepos = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; pdpmode = Cs2Area->reg.CR3 >> 8; // Convert Start Position to playFAD if (pdspos == 0xFFFFFF || pdpmode == 0xFF) // This still isn't right { // No Change } else if (pdspos & 0x800000) { // FAD Mode Cs2Area->playFAD = (pdspos & 0xFFFFF); Cs2SetupDefaultPlayStats(Cs2FADToTrack(Cs2Area->playFAD), 0); if (!(pdpmode & 0x80)) // Move pickup to start position Cs2Area->FAD = Cs2Area->playFAD; } else { // Track Mode // If track == 0, set it to the first available track, or something like that if (pdspos == 0) pdspos = 0x0100; if (!(pdpmode & 0x80)) { Cs2SetupDefaultPlayStats((u8)(pdspos >> 8), 1); Cs2Area->playFAD = Cs2Area->FAD; Cs2Area->track = (u8)(pdspos >> 8); Cs2Area->index = (u8)pdspos; } else { // Preserve Pickup Position Cs2SetupDefaultPlayStats((u8)(pdspos >> 8), 0); } } pdpmode &= 0x7F; // Only update max repeat if bits 0-6 aren't all set if (pdpmode != 0x7F) Cs2Area->maxrepeat = pdpmode; // Convert End Position to playendFAD if (pdepos == 0xFFFFFF) { // No Change } else if (pdepos & 0x800000) { // FAD Mode Cs2Area->playendFAD = Cs2Area->playFAD+(pdepos & 0xFFFFF); } else if (pdepos != 0) { // Track Mode if ((pdepos & 0xFF) == 0) Cs2Area->playendFAD = Cs2TrackToFAD((u16)(pdepos | 0x0063)); else Cs2Area->playendFAD = Cs2TrackToFAD((u16)pdepos); } else { // Default Mode Cs2Area->playendFAD = Cs2TrackToFAD(0xFFFF); } // setup play mode here #if CDDEBUG if (pdpmode != 0) CDLOG("cs2\t: playDisc: Unsupported play mode = %02X\n", pdpmode); #endif Cs2SetTiming(1); Cs2Area->status = CDB_STAT_PLAY; Cs2Area->playtype = CDB_PLAYTYPE_SECTOR; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SeekDisc(void) { if (Cs2Area->reg.CR1 & 0x80) { // Seek by FAD u32 sdFAD; sdFAD = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; if (sdFAD == 0xFFFFFF) Cs2Area->status = CDB_STAT_PAUSE; else { CDLOG("cs2\t: seekDisc - FAD Mode not supported\n"); } } else { // Were we given a valid track number? if (Cs2Area->reg.CR2 >> 8) { // Seek by index Cs2Area->status = CDB_STAT_PAUSE; Cs2SetupDefaultPlayStats((Cs2Area->reg.CR2 >> 8), 1); Cs2Area->index = Cs2Area->reg.CR2 & 0xFF; } else { // Error Cs2Area->status = CDB_STAT_STANDBY; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; Cs2Area->FAD = 0xFFFFFFFF; } } Cs2SetTiming(0); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSubcodeQRW(void) { // According to Tyranid's doc, the subcode type is stored in the low byte // of CR2. However, Sega's CDC library writes the type to the low byte // of CR1. Somehow I'd sooner believe Sega is right. switch(Cs2Area->reg.CR1 & 0xFF) { case 0: // Get Q Channel Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0; Cs2Area->reg.CR2 = 5; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; // setup transfer here(fix me) break; case 1: // Get RW Channel Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0; Cs2Area->reg.CR2 = 12; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; // setup transfer here(fix me) break; default: break; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetCDDeviceConnection(void) { u32 scdcfilternum; scdcfilternum = (Cs2Area->reg.CR3 >> 8); if (scdcfilternum == 0xFF) Cs2Area->outconcddev = NULL; else if (scdcfilternum < 0x24) Cs2Area->outconcddev = Cs2Area->filter + scdcfilternum; Cs2Area->outconcddevnum = (u8)scdcfilternum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetLastBufferDestination(void) { Cs2Area->reg.CR1 = (Cs2Area->status << 8); Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = Cs2Area->lastbuffer << 8; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterRange(void) { u8 sfrfilternum; sfrfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfrfilternum].FAD = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; Cs2Area->filter[sfrfilternum].range = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; // return default cd stats doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterSubheaderConditions(void) { u8 sfscfilternum; sfscfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfscfilternum].chan = Cs2Area->reg.CR1 & 0xFF; Cs2Area->filter[sfscfilternum].smmask = Cs2Area->reg.CR2 >> 8; Cs2Area->filter[sfscfilternum].cimask = Cs2Area->reg.CR2 & 0xFF; Cs2Area->filter[sfscfilternum].fid = Cs2Area->reg.CR3 & 0xFF;; Cs2Area->filter[sfscfilternum].smval = Cs2Area->reg.CR4 >> 8; Cs2Area->filter[sfscfilternum].cival = Cs2Area->reg.CR4 & 0xFF; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterSubheaderConditions(void) { u8 gfscfilternum; gfscfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->filter[gfscfilternum].chan; Cs2Area->reg.CR2 = (Cs2Area->filter[gfscfilternum].smmask << 8) | Cs2Area->filter[gfscfilternum].cimask; Cs2Area->reg.CR3 = Cs2Area->filter[gfscfilternum].fid; Cs2Area->reg.CR4 = (Cs2Area->filter[gfscfilternum].smval << 8) | Cs2Area->filter[gfscfilternum].cival; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterMode(void) { u8 sfmfilternum; sfmfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfmfilternum].mode = Cs2Area->reg.CR1 & 0xFF; if (Cs2Area->filter[sfmfilternum].mode & 0x80) { // Initialize filter conditions Cs2Area->filter[sfmfilternum].mode = 0; Cs2Area->filter[sfmfilternum].FAD = 0; Cs2Area->filter[sfmfilternum].range = 0; Cs2Area->filter[sfmfilternum].chan = 0; Cs2Area->filter[sfmfilternum].smmask = 0; Cs2Area->filter[sfmfilternum].cimask = 0; Cs2Area->filter[sfmfilternum].smval = 0; Cs2Area->filter[sfmfilternum].cival = 0; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterMode(void) { u8 gfmfilternum; gfmfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->filter[gfmfilternum].mode; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterConnection(void) { u8 sfcfilternum; sfcfilternum = Cs2Area->reg.CR3 >> 8; if (Cs2Area->reg.CR1 & 0x1) { // Set connection for true condition Cs2Area->filter[sfcfilternum].condtrue = Cs2Area->reg.CR2 >> 8; } if (Cs2Area->reg.CR1 & 0x2) { // Set connection for false condition Cs2Area->filter[sfcfilternum].condfalse = Cs2Area->reg.CR2 & 0xFF; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2ResetSelector(void) { // still needs a bit of work u32 i, i2; if ((Cs2Area->reg.CR1 & 0xFF) == 0) { // Reset specified partition buffer only u32 rsbufno = Cs2Area->reg.CR3 >> 8; // sort remaining blocks if (rsbufno < MAX_SELECTORS) { // clear partition for (i = 0; i < Cs2Area->partition[rsbufno].numblocks; i++) { Cs2FreeBlock(Cs2Area->partition[rsbufno].block[i]); Cs2Area->partition[rsbufno].block[i] = NULL; Cs2Area->partition[rsbufno].blocknum[i] = 0xFF; } Cs2Area->partition[rsbufno].size = -1; Cs2Area->partition[rsbufno].numblocks = 0; } if (Cs2Area->blockfreespace > 0) Cs2Area->isbufferfull = 0; if (Cs2Area->blockfreespace == 200) Cs2Area->isonesectorstored = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; return; } // parse flags and reset the specified area(fix me) if (Cs2Area->reg.CR1 & 0x80) { // reset false filter output connections for (i = 0; i < MAX_SELECTORS; i++) Cs2Area->filter[i].condfalse = 0xFF; } if (Cs2Area->reg.CR1 & 0x40) { // reset true filter output connections for (i = 0; i < MAX_SELECTORS; i++) Cs2Area->filter[i].condtrue = (u8)i; } if (Cs2Area->reg.CR1 & 0x10) { // reset filter conditions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->filter[i].FAD = 0; Cs2Area->filter[i].range = 0xFFFFFFFF; Cs2Area->filter[i].mode = 0; Cs2Area->filter[i].chan = 0; Cs2Area->filter[i].smmask = 0; Cs2Area->filter[i].cimask = 0; Cs2Area->filter[i].fid = 0; Cs2Area->filter[i].smval = 0; Cs2Area->filter[i].cival = 0; } } if (Cs2Area->reg.CR1 & 0x8) { // reset partition output connectors } if (Cs2Area->reg.CR1 & 0x4) { // reset partitions buffer data Cs2Area->isbufferfull = 0; // clear partitions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->partition[i].size = -1; Cs2Area->partition[i].numblocks = 0; for (i2 = 0; i2 < MAX_BLOCKS; i2++) { Cs2Area->partition[i].block[i2] = NULL; Cs2Area->partition[i].blocknum[i2] = 0xFF; } } // clear blocks for (i = 0; i < MAX_BLOCKS; i++) { Cs2Area->block[i].size = -1; memset(Cs2Area->block[i].data, 0, 2352); } Cs2Area->isonesectorstored = 0; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetBufferSize(void) { Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = (u16)Cs2Area->blockfreespace; Cs2Area->reg.CR3 = MAX_SELECTORS << 8; Cs2Area->reg.CR4 = MAX_BLOCKS; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorNumber(void) { u32 gsnbufno; gsnbufno = Cs2Area->reg.CR3 >> 8; if (Cs2Area->partition[gsnbufno].size == -1) Cs2Area->reg.CR4 = 0; else Cs2Area->reg.CR4 = Cs2Area->partition[gsnbufno].numblocks; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2CalculateActualSize(void) { u16 i; u32 casbufno; u16 cassectoffset; u16 casnumsect; cassectoffset = Cs2Area->reg.CR2; casbufno = Cs2Area->reg.CR3 >> 8; casnumsect = Cs2Area->reg.CR4; if (Cs2Area->partition[casbufno].size != 0) { Cs2Area->calcsize = 0; for (i = 0; i < casnumsect; i++) { if (Cs2Area->partition[casbufno].block[cassectoffset]) Cs2Area->calcsize += (Cs2Area->partition[casbufno].block[cassectoffset]->size / 2); } } else Cs2Area->calcsize = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetActualSize(void) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->calcsize >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16)Cs2Area->calcsize; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorInfo(void) { u32 gsisctnum; u32 gsibufno; gsisctnum = Cs2Area->reg.CR2 & 0xFF; gsibufno = Cs2Area->reg.CR3 >> 8; if (gsibufno < MAX_SELECTORS) { if (gsisctnum < Cs2Area->partition[gsibufno].numblocks) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->partition[gsibufno].block[gsisctnum]->FAD >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16)Cs2Area->partition[gsibufno].block[gsisctnum]->FAD; Cs2Area->reg.CR3 = (Cs2Area->partition[gsibufno].block[gsisctnum]->fn << 8) | Cs2Area->partition[gsibufno].block[gsisctnum]->cn; Cs2Area->reg.CR4 = (Cs2Area->partition[gsibufno].block[gsisctnum]->sm << 8) | Cs2Area->partition[gsibufno].block[gsisctnum]->ci; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; return; } else { CDLOG("cs2\t: getSectorInfo: Unsupported Partition Number\n"); } } Cs2Area->reg.CR1 = (CDB_STAT_REJECT << 8) | (Cs2Area->reg.CR1 & 0xFF); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetSectorLength(void) { switch (Cs2Area->reg.CR1 & 0xFF) { case 0: Cs2Area->getsectsize = 2048; break; case 1: Cs2Area->getsectsize = 2336; break; case 2: Cs2Area->getsectsize = 2340; break; case 3: Cs2Area->getsectsize = 2352; break; default: break; } switch (Cs2Area->reg.CR2 >> 8) { case 0: Cs2Area->putsectsize = 2048; break; case 1: Cs2Area->putsectsize = 2336; break; case 2: Cs2Area->putsectsize = 2340; break; case 3: Cs2Area->putsectsize = 2352; break; default: break; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// static INLINE void CalcSectorOffsetNumber(u32 bufno, u32 *sectoffset, u32 *sectnum) { if (*sectoffset == 0xFFFF) { // Last sector CDLOG("FIXME - Sector offset of 0xFFFF not supported\n"); } else if (*sectnum == 0xFFFF) { // From sectoffset to last sector in partition *sectnum = Cs2Area->partition[bufno].numblocks - *sectoffset; } } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorData(void) { u32 gsdsectoffset; u32 gsdbufno; u32 gsdsectnum; gsdsectoffset = Cs2Area->reg.CR2; gsdbufno = Cs2Area->reg.CR3 >> 8; gsdsectnum = Cs2Area->reg.CR4; if (gsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[gsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(gsdbufno, &gsdsectoffset, &gsdsectnum); // Setup Data Transfer Cs2Area->cdwnum = 0; Cs2Area->datatranstype = 0; Cs2Area->datatranspartition = Cs2Area->partition + gsdbufno; Cs2Area->datatranspartitionnum = (u8)gsdbufno; Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans = 0; Cs2Area->datatranssectpos = (u16)gsdsectoffset; Cs2Area->datasectstotrans = (u16)gsdsectnum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY | CDB_HIRQ_EHST; } ////////////////////////////////////////////////////////////////////////////// void Cs2DeleteSectorData(void) { u32 dsdsectoffset; u32 dsdbufno; u32 dsdsectnum; u32 i; dsdsectoffset = Cs2Area->reg.CR2; dsdbufno = Cs2Area->reg.CR3 >> 8; dsdsectnum = Cs2Area->reg.CR4; if (dsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[dsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(dsdbufno, &dsdsectoffset, &dsdsectnum); for (i = dsdsectoffset; i < (dsdsectoffset+dsdsectnum); i++) { Cs2Area->partition[dsdbufno].size -= Cs2Area->partition[dsdbufno].block[i]->size; Cs2FreeBlock(Cs2Area->partition[dsdbufno].block[i]); Cs2Area->partition[dsdbufno].block[i] = NULL; Cs2Area->partition[dsdbufno].blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(&Cs2Area->partition[dsdbufno]); Cs2Area->partition[dsdbufno].numblocks -= (u8)dsdsectnum; if (Cs2Area->blockfreespace == 200) Cs2Area->isonesectorstored = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetThenDeleteSectorData(void) { u32 gtdsdsectoffset; u32 gtdsdbufno; u32 gtdsdsectnum; gtdsdsectoffset = Cs2Area->reg.CR2; gtdsdbufno = Cs2Area->reg.CR3 >> 8; gtdsdsectnum = Cs2Area->reg.CR4; if (gtdsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[gtdsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(gtdsdbufno, >dsdsectoffset, >dsdsectnum); // Setup Data Transfer Cs2Area->cdwnum = 0; Cs2Area->datatranstype = 2; Cs2Area->datatranspartition = Cs2Area->partition + gtdsdbufno; Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans = 0; Cs2Area->datatranssectpos = (u16)gtdsdsectoffset; Cs2Area->datasectstotrans = (u16)gtdsdsectnum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY | CDB_HIRQ_EHST; return; } ////////////////////////////////////////////////////////////////////////////// void Cs2PutSectorData(void) { u32 psdfiltno; psdfiltno = Cs2Area->reg.CR3 >> 8; if (psdfiltno < MAX_SELECTORS) { // I'm not really sure what I'm supposed to really be doing or returning Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; } else { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; } } ////////////////////////////////////////////////////////////////////////////// void Cs2GetCopyError(void) { Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2ChangeDirectory(void) { u32 cdfilternum; cdfilternum = (Cs2Area->reg.CR3 >> 8); if (cdfilternum == 0xFF) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } else if (cdfilternum < 0x24) { if (Cs2ReadFileSystem(Cs2Area->filter + cdfilternum, ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4, 0) != 0) { CDLOG("cs2\t: ReadFileSystem failed\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2ReadDirectory(void) { u32 rdfilternum; rdfilternum = (Cs2Area->reg.CR3 >> 8); if (rdfilternum == 0xFF) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } else if (rdfilternum < 0x24) { if (Cs2ReadFileSystem(Cs2Area->filter + rdfilternum, ((Cs2Area->reg.CR3 & 0xFF) << 8) | Cs2Area->reg.CR4, 1) != 0) { CDLOG("cs2\t: ReadFileSystem failed\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFileSystemScope(void) { // may need to fix this Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = (u16)(Cs2Area->numfiles - 2); Cs2Area->reg.CR3 = 0x0100; Cs2Area->reg.CR4 = 0x0002; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFileInfo(void) { u32 gfifid; gfifid = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; if (gfifid == 0xFFFFFF) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = 2; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0x05F4; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } else { Cs2SetupFileInfoTransfer(gfifid); Cs2Area->transfercount = 0; Cs2Area->infotranstype = 1; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0x06; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2ReadFile(void) { u32 rfoffset, rffilternum, rffid, rfsize; rfoffset = ((Cs2Area->reg.CR1 & 0xFF) << 8) | Cs2Area->reg.CR2; rffilternum = Cs2Area->reg.CR3 >> 8; rffid = ((Cs2Area->reg.CR3 & 0xFF) << 8) | Cs2Area->reg.CR4; rfsize = ((Cs2Area->fileinfo[rffid].size + Cs2Area->getsectsize - 1) / Cs2Area->getsectsize) - rfoffset; Cs2SetupDefaultPlayStats(Cs2FADToTrack(Cs2Area->fileinfo[rffid].lba + rfoffset), 0); Cs2Area->maxrepeat = 0; Cs2Area->playFAD = Cs2Area->FAD = Cs2Area->fileinfo[rffid].lba + rfoffset; Cs2Area->playendFAD = Cs2Area->playFAD + rfsize; Cs2Area->options = 0x8; Cs2SetTiming(1); Cs2Area->outconcddev = Cs2Area->filter + rffilternum; Cs2Area->status = CDB_STAT_PLAY; Cs2Area->playtype = CDB_PLAYTYPE_FILE; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2AbortFile(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->isonesectorstored = 0; Cs2Area->datatranstype = -1; Cs2Area->cdwnum = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetStatus(void) { doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetInterrupt(void) { u32 mgiworkinterrupt; // mpeg interrupt should be retrieved here mgiworkinterrupt = 0; // mask interupt mgiworkinterrupt &= Cs2Area->mpegintmask; Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((mgiworkinterrupt >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16) mgiworkinterrupt; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetInterruptMask(void) { Cs2Area->mpegintmask = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegInit(void) { if (Cs2Area->mpgauth) Cs2Area->reg.CR1 = Cs2Area->status << 8; else Cs2Area->reg.CR1 = 0xFF00; // double-check this if (Cs2Area->reg.CR2 == 0x0001) // software timer/reset? Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM | CDB_HIRQ_MPED | CDB_HIRQ_MPST; else Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPED | CDB_HIRQ_MPST; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; // future mpeg-related variables should be initialized here } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetMode(void) { // fix me doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegPlay(void) { // fix me doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetDecodingMethod(void) { // fix me doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetConnection(void) { int mscnext = (Cs2Area->reg.CR3 >> 8); if (mscnext == 0) { // Current Cs2Area->mpegcon[0].audcon = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegcon[0].audlay = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegcon[0].audbufdivnum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegcon[0].vidcon = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegcon[0].vidlay = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegcon[0].vidbufdivnum = Cs2Area->reg.CR4 & 0xFF; } else { // Next Cs2Area->mpegcon[1].audcon = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegcon[1].audlay = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegcon[1].audbufdivnum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegcon[1].vidcon = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegcon[1].vidlay = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegcon[1].vidbufdivnum = Cs2Area->reg.CR4 & 0xFF; } doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetConnection(void) { int mgcnext = (Cs2Area->reg.CR3 >> 8); if (mgcnext == 0) { // Current Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegcon[0].audcon; Cs2Area->reg.CR2 = (Cs2Area->mpegcon[0].audlay << 8) | Cs2Area->mpegcon[0].audbufdivnum; Cs2Area->reg.CR3 = Cs2Area->mpegcon[0].vidcon; Cs2Area->reg.CR4 = (Cs2Area->mpegcon[0].vidlay << 8) | Cs2Area->mpegcon[0].vidbufdivnum; } else { // Next Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegcon[1].audcon; Cs2Area->reg.CR2 = (Cs2Area->mpegcon[1].audlay << 8) | Cs2Area->mpegcon[1].audbufdivnum; Cs2Area->reg.CR3 = Cs2Area->mpegcon[1].vidcon; Cs2Area->reg.CR4 = (Cs2Area->mpegcon[1].vidlay << 8) | Cs2Area->mpegcon[1].vidbufdivnum; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetStream(void) { int mssnext = (Cs2Area->reg.CR3 >> 8); if (mssnext == 0) { // Current Cs2Area->mpegstm[0].audstm = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegstm[0].audstmid = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegstm[0].audchannum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegstm[0].vidstm = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegstm[0].vidstmid = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegstm[0].vidchannum = Cs2Area->reg.CR4 & 0xFF; } else { // Next Cs2Area->mpegstm[1].audstm = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegstm[1].audstmid = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegstm[1].audchannum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegstm[1].vidstm = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegstm[1].vidstmid = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegstm[1].vidchannum = Cs2Area->reg.CR4 & 0xFF; } doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetStream(void) { int mgsnext = (Cs2Area->reg.CR3 >> 8); if (mgsnext == 0) { // Current Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegstm[0].audstm; Cs2Area->reg.CR2 = (Cs2Area->mpegstm[0].audstmid << 8) | Cs2Area->mpegstm[0].audchannum; Cs2Area->reg.CR3 = Cs2Area->mpegstm[0].vidstm; Cs2Area->reg.CR4 = (Cs2Area->mpegstm[0].vidstmid << 8) | Cs2Area->mpegstm[0].vidchannum; } else { // Next Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegstm[1].audstm; Cs2Area->reg.CR2 = (Cs2Area->mpegstm[1].audstmid << 8) | Cs2Area->mpegstm[1].audchannum; Cs2Area->reg.CR3 = Cs2Area->mpegstm[1].vidstm; Cs2Area->reg.CR4 = (Cs2Area->mpegstm[1].vidstmid << 8) | Cs2Area->mpegstm[1].vidchannum; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegDisplay(void) { // fix me(should be setting display setting) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetWindow(void) { // fix me(should be setting windows settings) // return default mpeg stats doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetBorderColor(void) { // fix me(should be setting border color) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetFade(void) { // fix me(should be setting fade setting) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetVideoEffects(void) { // fix me(should be setting video effects settings) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetLSI(void) { // fix me(should be setting the LSI, among other things) Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2CmdE0(void) { int mpegauth; mpegauth = Cs2Area->reg.CR2 & 0xFF; if ((Cs2Area->status & 0xF) != CDB_STAT_NODISC && (Cs2Area->status & 0xF) != CDB_STAT_OPEN) { // Set registers all to invalid values(aside from status) Cs2Area->status = CDB_STAT_BUSY; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0xFF; Cs2Area->reg.CR2 = 0xFFFF; Cs2Area->reg.CR3 = 0xFFFF; Cs2Area->reg.CR4 = 0xFFFF; if (mpegauth == 1) { Cs2Area->reg.HIRQ |= CDB_HIRQ_MPED; Cs2Area->mpgauth = 2; } else { // if authentication passes(obviously it always does), CDB_HIRQ_CSCT is set Cs2Area->isonesectorstored = 1; Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS | CDB_HIRQ_CSCT; Cs2Area->satauth = 4; } // Set registers all back to normal values Cs2Area->status = CDB_STAT_PAUSE; } else { if (mpegauth == 1) { Cs2Area->reg.HIRQ |= CDB_HIRQ_MPED; Cs2Area->mpgauth = 2; } else Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS | CDB_HIRQ_CSCT; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2CmdE1(void) { Cs2Area->reg.CR1 = (Cs2Area->status << 8); if (Cs2Area->reg.CR2) Cs2Area->reg.CR2 = Cs2Area->mpgauth; else Cs2Area->reg.CR2 = Cs2Area->satauth; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2CmdE2(void) { u16 i; FILE * mpgfp; partition_struct * mpgpartition; // fix me Cs2Area->mpgauth |= 0x300; Cs2Area->outconmpegrom = Cs2Area->filter + 0; Cs2Area->outconmpegromnum = 0; if (Cs2Area->mpegpath && (mpgfp = fopen(Cs2Area->mpegpath, "rb")) != NULL) { u32 readoffset = ((Cs2Area->reg.CR1 & 0xFF) << 8) | Cs2Area->reg.CR2; u16 readsize = Cs2Area->reg.CR4; fseek(mpgfp, readoffset * Cs2Area->getsectsize, SEEK_SET); if ((mpgpartition = Cs2GetPartition(Cs2Area->outconmpegrom)) != NULL && !Cs2Area->isbufferfull) { IOCheck_struct check; mpgpartition->size = 0; for (i = 0; i < readsize; i++) { mpgpartition->block[mpgpartition->numblocks] = Cs2AllocateBlock(&mpgpartition->blocknum[mpgpartition->numblocks]); if (mpgpartition->block[mpgpartition->numblocks] != NULL) { // read data yread(&check, (void *)mpgpartition->block[mpgpartition->numblocks]->data, 1, Cs2Area->getsectsize, mpgfp); mpgpartition->numblocks++; mpgpartition->size += Cs2Area->getsectsize; } } Cs2Area->isonesectorstored = 1; Cs2Area->reg.HIRQ |= CDB_HIRQ_CSCT; } fclose(mpgfp); } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPED; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2FADToTrack(u32 val) { int i; for (i = 0; i < 99; i++) { if (Cs2Area->TOC[i] == 0xFFFFFFFF) return 0xFF; if (val >= (Cs2Area->TOC[i] & 0xFFFFFF) && val < (Cs2Area->TOC[i + 1] & 0xFFFFFF)) return (i + 1); } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 Cs2TrackToFAD(u16 trackandindex) { if (trackandindex == 0xFFFF) // leadout position return (Cs2Area->TOC[101] & 0x00FFFFFF); if (trackandindex != 0x0000) { // regular track // (really, we should be fetching subcode q's here) if ((trackandindex & 0xFF) == 0x01) // Return Start of Track return (Cs2Area->TOC[(trackandindex >> 8) - 1] & 0x00FFFFFF); else if ((trackandindex & 0xFF) == 0x63) // Return End of Track return ((Cs2Area->TOC[(trackandindex >> 8)] & 0x00FFFFFF) - 1); } // assume it's leadin return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetupDefaultPlayStats(u8 track_number, int writeFAD) { if (track_number != 0xFF) { Cs2Area->options = 0; Cs2Area->repcnt = 0; Cs2Area->ctrladdr = (u8)(Cs2Area->TOC[track_number - 1] >> 24); Cs2Area->index = 1; Cs2Area->track = track_number; if (writeFAD) Cs2Area->FAD = Cs2Area->TOC[track_number - 1] & 0x00FFFFFF; } } ////////////////////////////////////////////////////////////////////////////// block_struct * Cs2AllocateBlock(u8 * blocknum) { u32 i; // find a free block for(i = 0; i < 200; i++) { if (Cs2Area->block[i].size == -1) { Cs2Area->blockfreespace--; if (Cs2Area->blockfreespace <= 0) Cs2Area->isbufferfull = 1; Cs2Area->block[i].size = Cs2Area->getsectsize; *blocknum = (u8)i; return (Cs2Area->block + i); } } Cs2Area->isbufferfull = 1; return NULL; } ////////////////////////////////////////////////////////////////////////////// void Cs2FreeBlock(block_struct * blk) { if (blk == NULL) return; blk->size = -1; Cs2Area->blockfreespace++; Cs2Area->isbufferfull = 0; Cs2Area->reg.HIRQ &= ~CDB_HIRQ_BFUL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SortBlocks(partition_struct * part) { unsigned int from, to; for (from = to = 0; from < MAX_BLOCKS; from++) { if (part->block[from] != NULL) { if (to != from) { part->block[to] = part->block[from]; } to++; } } for (; to < MAX_BLOCKS; to++) { part->block[to] = NULL; } } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2GetPartition(filter_struct * curfilter) { // go through various filter conditions here(fix me) return &Cs2Area->partition[curfilter->condtrue]; } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2FilterData(filter_struct * curfilter, int isaudio) { int condresults = 1; partition_struct * fltpartition = NULL; // fix me, this is pretty bad. Though I guess it's a start for (;;) { // detect which type of sector we're dealing with // If it's not mode 2, ignore the subheader conditions if (Cs2Area->workblock.data[0xF] == 0x02 && !isaudio) { // Mode 2 // go through various subheader filter conditions here(fix me) if (curfilter->mode & 0x01) { // File Number Check if (Cs2Area->workblock.fn != curfilter->fid) condresults = 0; } if (curfilter->mode & 0x02) { // Channel Number Check if (Cs2Area->workblock.cn != curfilter->chan) condresults = 0; } if (curfilter->mode & 0x04) { // Sub Mode Check if ((Cs2Area->workblock.sm & curfilter->smmask) != curfilter->smval) condresults = 0; } if (curfilter->mode & 0x08) { // Coding Information Check CDLOG("cs2\t: FilterData: Coding Information Check. Coding Information = %02X. Filter's Coding Information Mask = %02X, Coding Information Value = %02X\n", Cs2Area->workblock.ci, curfilter->cimask, curfilter->cival); if ((Cs2Area->workblock.ci & curfilter->cimask) != curfilter->cival) condresults = 0; } if (curfilter->mode & 0x10) { // Reverse Subheader Conditions CDLOG("cs2\t: FilterData: Reverse Subheader Conditions\n"); condresults ^= 1; } } if (curfilter->mode & 0x40) { // FAD Range Check if (Cs2Area->workblock.FAD < curfilter->FAD || Cs2Area->workblock.FAD > (curfilter->FAD+curfilter->range)) condresults = 0; } if (condresults == 1) { Cs2Area->lastbuffer = curfilter->condtrue; fltpartition = &Cs2Area->partition[curfilter->condtrue]; break; } else { Cs2Area->lastbuffer = curfilter->condfalse; if (curfilter->condfalse == 0xFF) return NULL; // loop and try filter that was connected to the false connector curfilter = &Cs2Area->filter[curfilter->condfalse]; } } // Allocate block fltpartition->block[fltpartition->numblocks] = Cs2AllocateBlock(&fltpartition->blocknum[fltpartition->numblocks]); if (fltpartition->block[fltpartition->numblocks] == NULL) return NULL; // Copy workblock settings to allocated block fltpartition->block[fltpartition->numblocks]->size = Cs2Area->workblock.size; fltpartition->block[fltpartition->numblocks]->FAD = Cs2Area->workblock.FAD; fltpartition->block[fltpartition->numblocks]->cn = Cs2Area->workblock.cn; fltpartition->block[fltpartition->numblocks]->fn = Cs2Area->workblock.fn; fltpartition->block[fltpartition->numblocks]->sm = Cs2Area->workblock.sm; fltpartition->block[fltpartition->numblocks]->ci = Cs2Area->workblock.ci; // convert raw sector to type specified in getsectsize switch(Cs2Area->workblock.size) { case 2048: // user data only if (Cs2Area->workblock.data[0xF] == 0x02) // m2f1 memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 24, Cs2Area->workblock.size); else // m1 memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 16, Cs2Area->workblock.size); break; case 2324: // m2f2 user data only memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 24, Cs2Area->workblock.size); break; case 2336: // m2f2 skip sync+header data memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 16, Cs2Area->workblock.size); break; case 2340: // m2f2 skip sync data memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 12, Cs2Area->workblock.size); break; case 2352: // Copy data as is memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data, Cs2Area->workblock.size); break; default: break; } // Modify Partition values if (fltpartition->size == -1) fltpartition->size = 0; fltpartition->size += fltpartition->block[fltpartition->numblocks]->size; fltpartition->numblocks++; return fltpartition; } ////////////////////////////////////////////////////////////////////////////// int Cs2CopyDirRecord(u8 * buffer, dirrec_struct * dirrec) { u8 * temp_pointer; temp_pointer = buffer; memcpy(&dirrec->recordsize, buffer, sizeof(dirrec->recordsize)); buffer += sizeof(dirrec->recordsize); memcpy(&dirrec->xarecordsize, buffer, sizeof(dirrec->xarecordsize)); buffer += sizeof(dirrec->xarecordsize); #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->lba); memcpy(&dirrec->lba, buffer, sizeof(dirrec->lba)); buffer += sizeof(dirrec->lba); #else memcpy(&dirrec->lba, buffer, sizeof(dirrec->lba)); buffer += (sizeof(dirrec->lba) * 2); #endif #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->size); memcpy(&dirrec->size, buffer, sizeof(dirrec->size)); buffer += sizeof(dirrec->size); #else memcpy(&dirrec->size, buffer, sizeof(dirrec->size)); buffer += (sizeof(dirrec->size) * 2); #endif dirrec->dateyear = buffer[0]; dirrec->datemonth = buffer[1]; dirrec->dateday = buffer[2]; dirrec->datehour = buffer[3]; dirrec->dateminute = buffer[4]; dirrec->datesecond = buffer[5]; dirrec->gmtoffset = buffer[6]; buffer += 7; dirrec->flags = buffer[0]; buffer += sizeof(dirrec->flags); dirrec->fileunitsize = buffer[0]; buffer += sizeof(dirrec->fileunitsize); dirrec->interleavegapsize = buffer[0]; buffer += sizeof(dirrec->interleavegapsize); #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->volumesequencenumber); memcpy(&dirrec->volumesequencenumber, buffer, sizeof(dirrec->volumesequencenumber)); buffer += sizeof(dirrec->volumesequencenumber); #else memcpy(&dirrec->volumesequencenumber, buffer, sizeof(dirrec->volumesequencenumber)); buffer += (sizeof(dirrec->volumesequencenumber) * 2); #endif dirrec->namelength = buffer[0]; buffer += sizeof(dirrec->namelength); memset(dirrec->name, 0, sizeof(dirrec->name)); memcpy(dirrec->name, buffer, dirrec->namelength); buffer += dirrec->namelength; // handle padding buffer += (1 - dirrec->namelength % 2); memset(&dirrec->xarecord, 0, sizeof(dirrec->xarecord)); // sadily, this is the best way I can think of for detecting XA records if ((dirrec->recordsize - (buffer - temp_pointer)) == 14) { memcpy(&dirrec->xarecord.groupid, buffer, sizeof(dirrec->xarecord.groupid)); buffer += sizeof(dirrec->xarecord.groupid); memcpy(&dirrec->xarecord.userid, buffer, sizeof(dirrec->xarecord.userid)); buffer += sizeof(dirrec->xarecord.userid); memcpy(&dirrec->xarecord.attributes, buffer, sizeof(dirrec->xarecord.attributes)); buffer += sizeof(dirrec->xarecord.attributes); #ifndef WORDS_BIGENDIAN // byte swap it dirrec->xarecord.attributes = ((dirrec->xarecord.attributes & 0xFF00) >> 8) + ((dirrec->xarecord.attributes & 0x00FF) << 8); #endif memcpy(&dirrec->xarecord.signature, buffer, sizeof(dirrec->xarecord.signature)); buffer += sizeof(dirrec->xarecord.signature); memcpy(&dirrec->xarecord.filenumber, buffer, sizeof(dirrec->xarecord.filenumber)); buffer += sizeof(dirrec->xarecord.filenumber); memcpy(dirrec->xarecord.reserved, buffer, sizeof(dirrec->xarecord.reserved)); buffer += sizeof(dirrec->xarecord.reserved); } return 0; } ////////////////////////////////////////////////////////////////////////////// int Cs2ReadFileSystem(filter_struct * curfilter, u32 fid, int isoffset) { u8 * workbuffer; u32 i; dirrec_struct dirrec; u8 numsectorsleft = 0; u32 curdirlba = 0; partition_struct * rfspartition; u32 blocksectsize = Cs2Area->getsectsize; Cs2Area->outconcddev = curfilter; if (isoffset) { // readDirectory operation // make sure we have a valid current directory if (Cs2Area->curdirsect == 0) return -1; Cs2Area->curdirfidoffset = fid - 2; curdirlba = Cs2Area->curdirsect; numsectorsleft = (u8)Cs2Area->curdirsize; } else { // changeDirectory operation if (fid == 0xFFFFFF) { // Figure out root directory's location // Read sector 16 if ((rfspartition = Cs2ReadUnFilteredSector(166)) == NULL) return -2; blocksectsize = rfspartition->block[rfspartition->numblocks - 1]->size; // Retrieve directory record's lba Cs2CopyDirRecord(rfspartition->block[rfspartition->numblocks - 1]->data + 0x9C, &dirrec); // Free Block rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; curdirlba = Cs2Area->curdirsect = dirrec.lba; Cs2Area->curdirsize = (dirrec.size / blocksectsize) - 1; numsectorsleft = (u8)Cs2Area->curdirsize; Cs2Area->curdirfidoffset = 0; } else { // Read in new directory record of specified directory // make sure we have a valid current directory if (Cs2Area->curdirsect == 0) return -1; curdirlba = Cs2Area->curdirsect = Cs2Area->fileinfo[fid - Cs2Area->curdirfidoffset].lba - 150; Cs2Area->curdirsize = (Cs2Area->fileinfo[fid - Cs2Area->curdirfidoffset].size / blocksectsize) - 1; numsectorsleft = (u8)Cs2Area->curdirsize; Cs2Area->curdirfidoffset = 0; } } // Make sure any old records are cleared memset(Cs2Area->fileinfo, 0, sizeof(dirrec_struct) * MAX_FILES); // now read in first sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; // Fill in first two entries of fileinfo for (i = 0; i < 2; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + i); Cs2Area->fileinfo[i].lba += 150; workbuffer += Cs2Area->fileinfo[i].recordsize; if (workbuffer[0] == 0) { Cs2Area->numfiles = i; break; } } // If doing a ReadDirectory operation, parse sector entries until we've // found the fid that matches fid if (isoffset) { for (i = 2; i < fid; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + 2); workbuffer += Cs2Area->fileinfo[2].recordsize; if (workbuffer[0] == 0) { if (numsectorsleft > 0) { // Free previous read sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; // Read in next sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; numsectorsleft--; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; } else { break; } } } } // Now generate the last 254 entries(the first two should've already been // generated earlier) for (i = 2; i < MAX_FILES; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + i); Cs2Area->fileinfo[i].lba += 150; workbuffer += Cs2Area->fileinfo[i].recordsize; if (workbuffer[0] == 0) { if (numsectorsleft > 0) { // Free previous read sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; // Read in next sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; numsectorsleft--; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; } else { Cs2Area->numfiles = i; break; } } } // Free the remaining sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; //#if CDDEBUG // for (i = 0; i < MAX_FILES; i++) // { // CDLOG("fileinfo[%d].name = %s\n", i, Cs2Area->fileinfo[i].name); // } //#endif return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetupFileInfoTransfer(u32 fid) { Cs2Area->transfileinfo[0] = (u8)(Cs2Area->fileinfo[fid].lba >> 24); Cs2Area->transfileinfo[1] = (u8)(Cs2Area->fileinfo[fid].lba >> 16); Cs2Area->transfileinfo[2] = (u8)(Cs2Area->fileinfo[fid].lba >> 8); Cs2Area->transfileinfo[3] = (u8)Cs2Area->fileinfo[fid].lba; Cs2Area->transfileinfo[4] = (u8)(Cs2Area->fileinfo[fid].size >> 24); Cs2Area->transfileinfo[5] = (u8)(Cs2Area->fileinfo[fid].size >> 16); Cs2Area->transfileinfo[6] = (u8)(Cs2Area->fileinfo[fid].size >> 8); Cs2Area->transfileinfo[7] = (u8)Cs2Area->fileinfo[fid].size; Cs2Area->transfileinfo[8] = Cs2Area->fileinfo[fid].interleavegapsize; Cs2Area->transfileinfo[9] = Cs2Area->fileinfo[fid].fileunitsize; Cs2Area->transfileinfo[10] = (u8) fid; Cs2Area->transfileinfo[11] = Cs2Area->fileinfo[fid].flags; } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2ReadUnFilteredSector(u32 rufsFAD) { partition_struct * rufspartition; char syncheader[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; if ((rufspartition = Cs2GetPartition(Cs2Area->outconcddev)) != NULL && !Cs2Area->isbufferfull) { // Allocate Block rufspartition->block[rufspartition->numblocks] = Cs2AllocateBlock(&rufspartition->blocknum[rufspartition->numblocks]); if (rufspartition->block[rufspartition->numblocks] == NULL) return NULL; // read a sector using cd interface function if (!Cs2Area->cdi->ReadSectorFAD(rufsFAD, Cs2Area->workblock.data)) return NULL; // convert raw sector to type specified in getsectsize switch(Cs2Area->getsectsize) { case 2048: // user data only if (Cs2Area->workblock.data[0xF] == 0x02) { // is it form1/form2 data? if (!(Cs2Area->workblock.data[0x12] & 0x20)) { // form 1 memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 24, 2048); Cs2Area->workblock.size = Cs2Area->getsectsize; } else { // form 2 memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 24, 2324); Cs2Area->workblock.size = 2324; } } else { memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 16, 2048); Cs2Area->workblock.size = Cs2Area->getsectsize; } break; case 2336: // skip sync+header data memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 16, 2336); Cs2Area->workblock.size = Cs2Area->getsectsize; break; case 2340: // skip sync data memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 12, 2340); Cs2Area->workblock.size = Cs2Area->getsectsize; break; case 2352: // no conversion needed Cs2Area->workblock.size = Cs2Area->getsectsize; break; default: break; } // if mode 2 track, setup the subheader values if (memcmp(syncheader, Cs2Area->workblock.data, 12) == 0 && Cs2Area->workblock.data[0xF] == 0x02) { rufspartition->block[rufspartition->numblocks]->fn = Cs2Area->workblock.data[0x10]; rufspartition->block[rufspartition->numblocks]->cn = Cs2Area->workblock.data[0x11]; rufspartition->block[rufspartition->numblocks]->sm = Cs2Area->workblock.data[0x12]; rufspartition->block[rufspartition->numblocks]->ci = Cs2Area->workblock.data[0x13]; } Cs2Area->workblock.FAD = rufsFAD; // Modify Partition values if (rufspartition->size == -1) rufspartition->size = 0; rufspartition->size += rufspartition->block[rufspartition->numblocks]->size; rufspartition->numblocks++; return rufspartition; } return NULL; } ////////////////////////////////////////////////////////////////////////////// int Cs2ReadFilteredSector(u32 rfsFAD, partition_struct **partition) { char syncheader[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; int isaudio = 0; if (Cs2Area->outconcddev != NULL && !Cs2Area->isbufferfull) { // read a sector using cd interface function to workblock.data if (!Cs2Area->cdi->ReadSectorFAD(rfsFAD, Cs2Area->workblock.data)) { *partition = NULL; return -2; } Cs2Area->workblock.size = Cs2Area->getsectsize; Cs2Area->workblock.FAD = rfsFAD; if (memcmp(syncheader, Cs2Area->workblock.data, 12) != 0) isaudio = 1; // force 1x speed if reading from an audio track Cs2Area->isaudio = isaudio; Cs2SetTiming(1); // if mode 2 track, setup the subheader values if (isaudio) { ScspReceiveCDDA(Cs2Area->workblock.data); *partition = NULL; return 0; } else if (Cs2Area->workblock.data[0xF] == 0x02) { // if it's form 2 data the sector size should be 2324 if (Cs2Area->workblock.data[0x12] & 0x20) Cs2Area->workblock.size = 2324; Cs2Area->workblock.fn = Cs2Area->workblock.data[0x10]; Cs2Area->workblock.cn = Cs2Area->workblock.data[0x11]; Cs2Area->workblock.sm = Cs2Area->workblock.data[0x12]; Cs2Area->workblock.ci = Cs2Area->workblock.data[0x13]; } // pass workblock to filter function(after it identifies partition, // it should allocate the partition block, setup/change the partition // values, and copy workblock to the allocated block) *partition = Cs2FilterData(Cs2Area->outconcddev, isaudio); return 0; } *partition = NULL; return -1; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2GetIP(int autoregion) { partition_struct * gripartition; u8 ret = 0; Cs2Area->outconcddev = Cs2Area->filter + 0; Cs2Area->outconcddevnum = 0; // read in lba 0/FAD 150 if ((gripartition = Cs2ReadUnFilteredSector(150)) != NULL) { char *buf=(char*)gripartition->block[gripartition->numblocks - 1]->data; // Make sure we're dealing with a saturn game if (memcmp(buf, "SEGA SEGASATURN", 15) == 0) { memcpy(cdip->system, buf, 16); cdip->system[16]='\0'; memcpy(cdip->company, buf+0x10, 16); cdip->company[16]='\0'; sscanf(buf+0x20, "%s", cdip->itemnum); memcpy(cdip->version, buf+0x2A, 6); cdip->version[6]='\0'; sprintf(cdip->date, "%c%c/%c%c/%c%c%c%c", buf[0x34], buf[0x35], buf[0x36], buf[0x37], buf[0x30], buf[0x31], buf[0x32], buf[0x33]); sscanf(buf+0x38, "%s", cdip->cdinfo); sscanf(buf+0x40, "%s", cdip->region); sscanf(buf+0x50, "%s", cdip->peripheral); memcpy(cdip->gamename, buf+0x60, 112); cdip->gamename[112]='\0'; #ifdef WORDS_BIGENDIAN memcpy(&cdip->ipsize, buf+0xE0, sizeof(u32)); memcpy(&cdip->msh2stack, buf+0xE8, sizeof(u32)); memcpy(&cdip->ssh2stack, buf+0xEC, sizeof(u32)); memcpy(&cdip->firstprogaddr, buf+0xF0, sizeof(u32)); memcpy(&cdip->firstprogsize, buf+0xF4, sizeof(u32)); #else cdip->ipsize = (buf[0xE0] << 24) | (buf[0xE1] << 16) | (buf[0xE2] << 8) | buf[0xE3]; cdip->msh2stack = (buf[0xE8] << 24) | (buf[0xE9] << 16) | (buf[0xEA] << 8) | buf[0xEB]; cdip->ssh2stack = (buf[0xEC] << 24) | (buf[0xED] << 16) | (buf[0xEE] << 8) | buf[0xEF]; cdip->firstprogaddr = (buf[0xF0] << 24) | (buf[0xF1] << 16) | (buf[0xF2] << 8) | buf[0xF3]; cdip->firstprogsize = (buf[0xF4] << 24) | (buf[0xF5] << 16) | (buf[0xF6] << 8) | buf[0xF7]; #endif if (autoregion) { // Read first available region, that'll be what we'll use switch (cdip->region[0]) { case 'J': ret = 1; break; case 'T': ret = 2; break; case 'U': ret = 4; break; case 'B': ret = 5; break; case 'K': ret = 6; break; case 'A': ret = 0xA; break; case 'E': ret = 0xC; break; case 'L': ret = 0xD; break; default: break; } } } // Free Block gripartition->size -= gripartition->block[gripartition->numblocks - 1]->size; Cs2FreeBlock(gripartition->block[gripartition->numblocks - 1]); gripartition->blocknum[gripartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(gripartition); gripartition->numblocks -= 1; } return ret; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2GetRegionID(void) { return Cs2GetIP(1); } ////////////////////////////////////////////////////////////////////////////// int Cs2SaveState(FILE * fp) { int offset, i; IOCheck_struct check; // This is mostly kludge, but it will have to do until I have time to rewrite it all offset = StateWriteHeader(fp, "CS2 ", 2); // Write cart type ywrite(&check, (void *) &Cs2Area->carttype, 4, 1, fp); // Write cd block registers ywrite(&check, (void *) &Cs2Area->reg, sizeof(blockregs_struct), 1, fp); // Write current Status variables(needs a rewrite) ywrite(&check, (void *) &Cs2Area->FAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->status, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->options, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->repcnt, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->ctrladdr, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->track, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->index, 1, 1, fp); // Write other cd block internal variables ywrite(&check, (void *) &Cs2Area->satauth, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->mpgauth, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->transfercount, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->cdwnum, 4, 1, fp); ywrite(&check, (void *) Cs2Area->TOC, 4, 102, fp); ywrite(&check, (void *) &Cs2Area->playFAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->playendFAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->getsectsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->putsectsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->calcsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->infotranstype, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranstype, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->isonesectorstored, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isdiskchanged, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isbufferfull, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->speed1x, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isaudio, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->transfileinfo, 1, 12, fp); ywrite(&check, (void *) &Cs2Area->lastbuffer, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->_command, 1, 1, fp); { u32 temp = (Cs2Area->_periodictiming + 3) / 3; ywrite(&check, (void *) &temp, 4, 1, fp); } ywrite(&check, (void *) &Cs2Area->_commandtiming, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->outconcddevnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegfbnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegbufnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegromnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconhostnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranspartitionnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->datatransoffset, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datanumsecttrans, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranssectpos, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->datasectstotrans, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->blockfreespace, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->curdirsect, 4, 1, fp); // Write CD buffer ywrite(&check, (void *)Cs2Area->block, sizeof(block_struct), MAX_BLOCKS, fp); // Write partition data for (i = 0; i < MAX_SELECTORS; i++) { ywrite(&check, (void *)&Cs2Area->partition[i].size, 4, 1, fp); ywrite(&check, (void *)Cs2Area->partition[i].blocknum, 1, MAX_BLOCKS, fp); ywrite(&check, (void *)&Cs2Area->partition[i].numblocks, 1, 1, fp); } // Write filter data ywrite(&check, (void *)Cs2Area->filter, sizeof(filter_struct), MAX_SELECTORS, fp); // Write File Info Table ywrite(&check, (void *)Cs2Area->fileinfo, sizeof(dirrec_struct), MAX_FILES, fp); // Write MPEG card registers here // Write current MPEG card status variables ywrite(&check, (void *)&Cs2Area->actionstatus, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->pictureinfo, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->mpegaudiostatus, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->mpegvideostatus, 2, 1, fp); ywrite(&check, (void *)&Cs2Area->vcounter, 2, 1, fp); // Write other MPEG card internal variables ywrite(&check, (void *)&Cs2Area->mpegintmask, 4, 1, fp); ywrite(&check, (void *)Cs2Area->mpegcon, sizeof(mpegcon_struct), 2, fp); ywrite(&check, (void *)Cs2Area->mpegstm, sizeof(mpegstm_struct), 2, fp); return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int Cs2LoadState(FILE * fp, int version, int size) { int i, i2; IOCheck_struct check; // This is mostly kludge, but it will have to do until I have time to rewrite it all // Read cart type yread(&check, (void *)&Cs2Area->carttype, 4, 1, fp); // Read cd block registers yread(&check, (void *)&Cs2Area->reg, sizeof(blockregs_struct), 1, fp); // Read current Status variables(needs a reRead) yread(&check, (void *)&Cs2Area->FAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->status, 1, 1, fp); yread(&check, (void *)&Cs2Area->options, 1, 1, fp); yread(&check, (void *)&Cs2Area->repcnt, 1, 1, fp); yread(&check, (void *)&Cs2Area->ctrladdr, 1, 1, fp); yread(&check, (void *)&Cs2Area->track, 1, 1, fp); yread(&check, (void *)&Cs2Area->index, 1, 1, fp); // Read other cd block internal variables yread(&check, (void *)&Cs2Area->satauth, 2, 1, fp); yread(&check, (void *)&Cs2Area->mpgauth, 2, 1, fp); yread(&check, (void *)&Cs2Area->transfercount, 4, 1, fp); yread(&check, (void *)&Cs2Area->cdwnum, 4, 1, fp); yread(&check, (void *)Cs2Area->TOC, 4, 102, fp); yread(&check, (void *)&Cs2Area->playFAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->playendFAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->getsectsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->putsectsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->calcsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->infotranstype, 4, 1, fp); yread(&check, (void *)&Cs2Area->datatranstype, 4, 1, fp); yread(&check, (void *)&Cs2Area->isonesectorstored, 1, 1, fp); yread(&check, (void *)&Cs2Area->isdiskchanged, 1, 1, fp); yread(&check, (void *)&Cs2Area->isbufferfull, 1, 1, fp); yread(&check, (void *)&Cs2Area->speed1x, 1, 1, fp); if (version > 1) yread(&check, (void *)&Cs2Area->isaudio, 1, 1, fp); yread(&check, (void *)&Cs2Area->transfileinfo, 1, 12, fp); yread(&check, (void *)&Cs2Area->lastbuffer, 1, 1, fp); yread(&check, (void *)&Cs2Area->_command, 1, 1, fp); { u32 temp; yread(&check, (void *)&temp, 4, 1, fp); // Derive the actual, accurate value (always a multiple of 10) Cs2Area->_periodictiming = ((temp * 3) / 10) * 10; } yread(&check, (void *)&Cs2Area->_commandtiming, 4, 1, fp); yread(&check, (void *)&Cs2Area->outconcddevnum, 1, 1, fp); if (Cs2Area->outconcddevnum == 0xFF) Cs2Area->outconcddev = NULL; else Cs2Area->outconcddev = Cs2Area->filter + Cs2Area->outconcddevnum; yread(&check, (void *)&Cs2Area->outconmpegfbnum, 1, 1, fp); if (Cs2Area->outconmpegfbnum == 0xFF) Cs2Area->outconmpegfb = NULL; else Cs2Area->outconmpegfb = Cs2Area->filter + Cs2Area->outconmpegfbnum; yread(&check, (void *)&Cs2Area->outconmpegbufnum, 1, 1, fp); if (Cs2Area->outconmpegbufnum == 0xFF) Cs2Area->outconmpegbuf = NULL; else Cs2Area->outconmpegbuf = Cs2Area->filter + Cs2Area->outconmpegbufnum; yread(&check, (void *)&Cs2Area->outconmpegromnum, 1, 1, fp); if (Cs2Area->outconmpegromnum == 0xFF) Cs2Area->outconmpegrom = NULL; else Cs2Area->outconmpegrom = Cs2Area->filter + Cs2Area->outconmpegromnum; yread(&check, (void *)&Cs2Area->outconhostnum, 1, 1, fp); if (Cs2Area->outconhostnum == 0xFF) Cs2Area->outconhost = NULL; else Cs2Area->outconhost = Cs2Area->filter + Cs2Area->outconhostnum; yread(&check, (void *)&Cs2Area->datatranspartitionnum, 1, 1, fp); yread(&check, (void *)&Cs2Area->datatransoffset, 4, 1, fp); yread(&check, (void *)&Cs2Area->datanumsecttrans, 4, 1, fp); yread(&check, (void *)&Cs2Area->datatranssectpos, 2, 1, fp); yread(&check, (void *)&Cs2Area->datasectstotrans, 2, 1, fp); yread(&check, (void *)&Cs2Area->blockfreespace, 4, 1, fp); yread(&check, (void *)&Cs2Area->curdirsect, 4, 1, fp); // Read CD buffer yread(&check, (void *)Cs2Area->block, sizeof(block_struct), MAX_BLOCKS, fp); // Read partition data for (i = 0; i < MAX_SELECTORS; i++) { yread(&check, (void *)&Cs2Area->partition[i].size, 4, 1, fp); yread(&check, (void *)Cs2Area->partition[i].blocknum, 1, MAX_BLOCKS, fp); yread(&check, (void *)&Cs2Area->partition[i].numblocks, 1, 1, fp); for (i2 = 0; i2 < MAX_BLOCKS; i2++) { if (Cs2Area->partition[i].blocknum[i2] == 0xFF) Cs2Area->partition[i].block[i2] = NULL; else Cs2Area->partition[i].block[i2] = Cs2Area->block + Cs2Area->partition[i].blocknum[i2]; } } // Read filter data yread(&check, (void *)Cs2Area->filter, sizeof(filter_struct), MAX_SELECTORS, fp); // Read File Info Table yread(&check, (void *)Cs2Area->fileinfo, sizeof(dirrec_struct), MAX_FILES, fp); // Read MPEG card registers here // Read current MPEG card status variables yread(&check, (void *)&Cs2Area->actionstatus, 1, 1, fp); yread(&check, (void *)&Cs2Area->pictureinfo, 1, 1, fp); yread(&check, (void *)&Cs2Area->mpegaudiostatus, 1, 1, fp); yread(&check, (void *)&Cs2Area->mpegvideostatus, 2, 1, fp); yread(&check, (void *)&Cs2Area->vcounter, 2, 1, fp); // Read other MPEG card internal variables yread(&check, (void *)&Cs2Area->mpegintmask, 4, 1, fp); yread(&check, (void *)Cs2Area->mpegcon, sizeof(mpegcon_struct), 2, fp); yread(&check, (void *)Cs2Area->mpegstm, sizeof(mpegstm_struct), 2, fp); return size; } //////////////////////////////////////////////////////////////////////////////