BizHawk/yabause/src/cs2.c

3721 lines
118 KiB
C

/* 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 <stdlib.h>
#include <ctype.h>
#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, &gtdsdsectoffset, &gtdsdsectnum);
// 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;
}
//////////////////////////////////////////////////////////////////////////////