Pcsx2: Added experimental mtap support, must be enabled through pad plugin. Fixed bug in default PADfreeze function that would fail to load states created with LilyPad when using other pad plugins. Added support for disconnected pads (Mostly a convenience for mtap support, for games that use pad presence to assign pads to players).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@854 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
mattmenke 2009-03-29 06:24:28 +00:00
parent e3b40d1933
commit ee7008ded8
4 changed files with 216 additions and 65 deletions

View File

@ -5,12 +5,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@ -72,6 +72,8 @@ _PADconfigure PAD1configure;
_PADtest PAD1test;
_PADabout PAD1about;
_PADfreeze PAD1freeze;
_PADsetSlot PAD1setSlot;
_PADqueryMtap PAD1queryMtap;
// PAD2
_PADinit PAD2init;
@ -89,6 +91,8 @@ _PADconfigure PAD2configure;
_PADtest PAD2test;
_PADabout PAD2about;
_PADfreeze PAD2freeze;
_PADsetSlot PAD2setSlot;
_PADqueryMtap PAD2queryMtap;
// SIO[2]
_SIOinit SIOinit[2][9];
@ -223,7 +227,7 @@ USBhandler usbHandler;
const char* errString = SysLibError(); \
Msgbox::Alert("%s: Error loading %hs: %s", params &filename, #name, errString); \
return -1; \
}
}
#define MapSymbol(name) MapSymbolVar(name,name)
#define MapSymbol_Fallback(name,fallback) MapSymbolVar_Fallback(name,name,fallback)
@ -332,7 +336,9 @@ void *PAD1plugin;
void CALLBACK PAD1_configure() {}
void CALLBACK PAD1_about() {}
s32 CALLBACK PAD1_test() { return 0; }
s32 CALLBACK PAD1_freeze(int mode, freezeData *data) { data->size = 0; return 0; }
s32 CALLBACK PAD1_freeze(int mode, freezeData *data) { if (mode == FREEZE_SIZE) data->size = 0; return 0; }
s32 CALLBACK PAD1_setSlot(u8 port, u8 slot) { return slot == 1; }
s32 CALLBACK PAD1_queryMtap(u8 port) { return 0; }
int LoadPAD1plugin(const string& filename) {
void *drv;
@ -356,6 +362,8 @@ int LoadPAD1plugin(const string& filename) {
MapSymbolPAD_Fallback(PAD1,PAD,about);
MapSymbolPAD_Fallback(PAD1,PAD,test);
MapSymbolPAD_Fallback(PAD1,PAD,freeze);
MapSymbolPAD_Fallback(PAD1,PAD,setSlot);
MapSymbolPAD_Fallback(PAD1,PAD,queryMtap);
return 0;
}
@ -365,7 +373,9 @@ void *PAD2plugin;
void CALLBACK PAD2_configure() {}
void CALLBACK PAD2_about() {}
s32 CALLBACK PAD2_test() { return 0; }
s32 CALLBACK PAD2_freeze(int mode, freezeData *data) { data->size = 0; return 0; }
s32 CALLBACK PAD2_freeze(int mode, freezeData *data) { if (mode == FREEZE_SIZE) data->size = 0; return 0; }
s32 CALLBACK PAD2_setSlot(u8 port, u8 slot) { return slot == 1; }
s32 CALLBACK PAD2_queryMtap(u8 port) { return 0; }
int LoadPAD2plugin(const string& filename) {
void *drv;
@ -389,6 +399,8 @@ int LoadPAD2plugin(const string& filename) {
MapSymbolPAD_Fallback(PAD2,PAD,about);
MapSymbolPAD_Fallback(PAD2,PAD,test);
MapSymbolPAD_Fallback(PAD2,PAD,freeze);
MapSymbolPAD_Fallback(PAD2,PAD,setSlot);
MapSymbolPAD_Fallback(PAD2,PAD,queryMtap);
return 0;
}
@ -413,11 +425,11 @@ int LoadSPU2plugin(const string& filename) {
MapSymbol_Error(SPU2close);
MapSymbol_Error(SPU2write);
MapSymbol_Error(SPU2read);
MapSymbol_Error(SPU2readDMA4Mem);
MapSymbol_Error(SPU2writeDMA4Mem);
MapSymbol_Error(SPU2readDMA4Mem);
MapSymbol_Error(SPU2writeDMA4Mem);
MapSymbol_Error(SPU2interruptDMA4);
MapSymbol_Error(SPU2readDMA7Mem);
MapSymbol_Error(SPU2writeDMA7Mem);
MapSymbol_Error(SPU2readDMA7Mem);
MapSymbol_Error(SPU2writeDMA7Mem);
MapSymbol_Error(SPU2interruptDMA7);
MapSymbol(SPU2setDMABaseAddr);
MapSymbol_Error(SPU2ReadMemAddr);
@ -537,7 +549,7 @@ int LoadUSBplugin(const string& filename) {
MapSymbol_Error(USBirqCallback);
MapSymbol_Error(USBirqHandler);
MapSymbol_Error(USBsetRAM);
MapSymbol(USBasync);
MapSymbol_Fallback(USBfreeze,USB_freeze);
@ -659,7 +671,7 @@ void ShutdownPlugins()
if( GSshutdown != NULL )
GSshutdown();
if( PAD1shutdown != NULL )
PAD1shutdown();
if( PAD2shutdown != NULL )
@ -704,7 +716,7 @@ int OpenPlugins(const char* pTitleFilename)
chdir(MAIN_DIR);
chdir(Config.PluginsDir);
if( pTitleFilename != NULL && pTitleFilename[0] != '/' )
if( pTitleFilename != NULL && pTitleFilename[0] != '/' )
{
// because we are changing the dir, we have to set a new title if it is a relative dir
sprintf(pNewTitle, "%s/%s", file, pTitleFilename);
@ -820,7 +832,7 @@ OpenError:
void ClosePlugins( bool closegs )
{
// Close pads first since they attatch to the GS's window.
CLOSE_PLUGIN( PAD1 );
CLOSE_PLUGIN( PAD2 );
@ -844,7 +856,7 @@ void ClosePlugins( bool closegs )
CLOSE_PLUGIN( USB );
CLOSE_PLUGIN( FW );
CLOSE_PLUGIN( SPU2 );
// More special treatment for the GS. It needs a complete shutdown and re-init
// or else it will tend to error out when we try to use it again.
if( 0 ) //closegs )
@ -895,7 +907,7 @@ void ReleasePlugins()
void PluginsResetGS()
{
// PADs are tied to the GS window, so shut them down together with the GS.
CLOSE_PLUGIN( PAD1 );
CLOSE_PLUGIN( PAD2 );

View File

@ -31,7 +31,7 @@
// the lower 16 bit value. IF the change is breaking of all compatibility with old
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
static const u32 g_SaveVersion = 0x8b410000;
static const u32 g_SaveVersion = 0x8b410001;
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
// between the GS saving function and the MTGS's needs. :)

View File

@ -5,12 +5,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@ -45,6 +45,17 @@ __forceinline void SIO_INT()
#define SIO_FORCEINLINE __forceinline
#endif
// Currently only check if pad wants mtap to be active.
// Could lets PCSX2 have its own options, if anyone ever
// wants to add support for using the extra memcard slots.
static bool IsMtapPresent( uint port ) {
switch(port) {
case 1: return 0 != PAD1queryMtap(port);
case 2: return 0 != PAD2queryMtap(port);
}
return 0;
}
static void _ReadMcd(u8 *data, u32 adr, int size) {
MemoryCard::Read(sio.GetMemcardIndex(), data, adr, size);
}
@ -73,7 +84,7 @@ void sioInit()
sio.StatReg = TX_RDY | TX_EMPTY;
sio.packetsize = 0;
sio.terminator =0x55; // Command terminator 'U'
MemoryCard::Init();
}
@ -138,6 +149,13 @@ void SIO_CommandWrite(u8 value,int way) {
if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
SIO_INT();
return;
case 3:
// No pad connected.
sio.parp++;
sio.bufcount = 6;
if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
SIO_INT();
return;
}
// MEMORY CARD COMMANDS
@ -150,28 +168,28 @@ void SIO_CommandWrite(u8 value,int way) {
switch (value) {
case 0x11: // RESET
PAD_LOG("RESET MEMORY CARD");
sio.bufcount = 8;
sio.bufcount = 8;
memset8_obj<0xff>(sio.buf);
sio.buf[3] = sio.terminator;
sio.buf[2] = '+';
sio.mcdst = 99;
sio.mcdst = 99;
sio2.packet.recvVal3 = 0x8c;
break;
case 0x12: // RESET
sio.bufcount = 8;
sio.bufcount = 8;
memset8_obj<0xff>(sio.buf);
sio.buf[3] = sio.terminator;
sio.buf[2] = '+';
sio.mcdst = 99;
sio.mcdst = 99;
sio2.packet.recvVal3 = 0x8c;
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x81: // COMMIT
sio.bufcount = 8;
sio.bufcount = 8;
memset8_obj<0xff>(sio.buf);
sio.mcdst = 99;
sio.mcdst = 99;
sio.buf[3] = sio.terminator;
sio.buf[2] = '+';
sio2.packet.recvVal3 = 0x8c;
@ -182,31 +200,31 @@ void SIO_CommandWrite(u8 value,int way) {
}
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x21:
case 0x22:
case 0x21:
case 0x22:
case 0x23: // SECTOR SET
sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0;
memset8_obj<0xff>(sio.buf);
sio2.packet.recvVal3 = 0x8c;
sio2.packet.recvVal3 = 0x8c;
sio.buf[8]=sio.terminator;
sio.buf[7]='+';
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x24:
case 0x24:
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x25:
case 0x25:
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x26:
sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83;
case 0x26:
sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83;
memset8_obj<0xff>(sio.buf);
memcpy(&sio.buf[2], &mc_command_0x26, sizeof(mc_command_0x26));
sio.buf[12]=sio.terminator;
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0x27:
case 0x28:
case 0x27:
case 0x28:
case 0xBF:
sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b;
memset8_obj<0xff>(sio.buf);
@ -219,8 +237,8 @@ void SIO_CommandWrite(u8 value,int way) {
case 0x82:
if(value==0x82 && sio.lastsector==sio.sector) sio.mode = 2;
if(value==0x42) sio.mode = 0;
if(value==0x43) sio.lastsector = sio.sector; // Reading
if(value==0x43) sio.lastsector = sio.sector; // Reading
sio.bufcount =133; sio.mcdst = 99;
memset8_obj<0xff>(sio.buf);
sio.buf[133]=sio.terminator;
@ -229,12 +247,12 @@ void SIO_CommandWrite(u8 value,int way) {
break;
case 0xf0:
case 0xf1:
case 0xf2:
sio.mcdst = 99;
case 0xf2:
sio.mcdst = 99;
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
case 0xf3:
case 0xf7:
case 0xf7:
sio.bufcount = 4; sio.mcdst = 99;
memset8_obj<0xff>(sio.buf);
sio.buf[4]=sio.terminator;
@ -248,13 +266,13 @@ void SIO_CommandWrite(u8 value,int way) {
break;
case 0x57:
sio.rdwr = 2; memset8_obj<0xff>(sio.buf);
sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
break;
default:
sio.mcdst = 0;
memset8_obj<0xff>(sio.buf);
sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
MEMCARDS_LOG("Unknown MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
}
sio.mc_command=value;
@ -302,11 +320,11 @@ void SIO_CommandWrite(u8 value,int way) {
if(sio.parp == 2) {
sio.buf[2] = '+';
sio.buf[3] = sio.terminator;
//if(value == 0) sio.buf[4] = 0xFF;
//if(value == 0) sio.buf[4] = 0xFF;
sio.buf[4] = 0x55;
MEMCARDS_LOG("MC(%d) GET TERMINATOR command 0x%02X", sio.GetMemcardIndex()+1, value);
}
}
break;
// WRITE DATA
case 0x42:
@ -316,7 +334,7 @@ void SIO_CommandWrite(u8 value,int way) {
sio.buf[sio.bufcount-1]='+';
sio.buf[sio.bufcount]=sio.terminator;
MEMCARDS_LOG("MC(%d) WRITE command 0x%02X\n\n\n\n", sio.GetMemcardIndex()+1, value);
}
}
else
if ((sio.parp>2) && (sio.parp<sio.bufcount-2)) {
sio.buf[sio.parp]=value;
@ -341,7 +359,7 @@ void SIO_CommandWrite(u8 value,int way) {
sio.buf[3]='+';
MEMCARDS_LOG("MC(%d) READ command 0x%02X", sio.GetMemcardIndex()+1, value);
_ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value);
/*if(sio.mode==2)
/*if(sio.mode==2)
{
int j;
for(j=0; j < value; j++)
@ -412,19 +430,42 @@ void SIO_CommandWrite(u8 value,int way) {
return;
}
switch (sio.mtapst)
static int test;
switch (sio.mtapst)
{
case 0x1:
test = value;
sio.packetsize++;
sio.parp = 1;
SIO_INT();
switch(value) {
case 0x12: sio.mtapst = 2; sio.bufcount = 5; break;
case 0x13: sio.mtapst = 2; sio.bufcount = 5; break;
case 0x21: sio.mtapst = 2; sio.bufcount = 6; break;
case 0x12:
// Query number of pads supported.
sio.buf[3] = 4;
sio.mtapst = 2;
sio.bufcount = 5;
break;
case 0x13:
// Query number of memcards supported.
sio.buf[3] = 4;
sio.mtapst = 2;
sio.bufcount = 5;
break;
case 0x21:
// Set pad slot.
sio.mtapst = 0x21;
sio.bufcount = 6; // No idea why this is 6, saved from old code.
break;
case 0x22:
// Set memcard slot.
sio.mtapst = 0x22;
sio.bufcount = 6; // No idea why this is 6, saved from old code.
break;
}
sio.buf[sio.bufcount]='Z';
// These were taken from old code. No idea if they're needed.
// Don't seem to break anything, at least.
sio.buf[sio.bufcount-1]='+';
sio.buf[sio.bufcount]='Z';
return;
case 0x2:
sio.packetsize++;
@ -432,8 +473,42 @@ void SIO_CommandWrite(u8 value,int way) {
if (sio.bufcount<=sio.parp) sio.mcdst = 0;
SIO_INT();
return;
case 0x21:
sio.packetsize++;
sio.parp++;
sio.mtapst = 2;
switch (sio.CtrlReg&0x2002) {
case 0x0002:
// Not sure if these checks are absolutely needed, but
// prefer to be safe.
if (IsMtapPresent(1))
sio.activePadSlot[0] = value;
break;
case 0x2002:
if (IsMtapPresent(2))
sio.activePadSlot[1] = value;
break;
}
SIO_INT();
return;
case 0x22:
sio.packetsize++;
sio.parp++;
sio.mtapst = 2;
switch (sio.CtrlReg&0x2002) {
case 0x0002:
if (IsMtapPresent(1))
sio.activeMemcardSlot[0] = value;
break;
case 0x2002:
if (IsMtapPresent(2))
sio.activeMemcardSlot[1] = value;
break;
}
SIO_INT();
return;
}
if(sio.count == 1 || way == 0) InitializeSIO(value);
}
@ -444,17 +519,36 @@ void InitializeSIO(u8 value)
sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
sio.StatReg |= RX_RDY; // Transfer is Ready
switch (sio.CtrlReg&0x2002) {
case 0x0002: sio.buf[0] = PAD1startPoll(1); break;
case 0x2002: sio.buf[0] = PAD2startPoll(2); break;
}
sio.bufcount = 2;
sio.parp = 0;
sio.padst = 1;
sio.packetsize = 1;
sio.count = 0;
sio2.packet.recvVal1 = 0x1100; // Pad is present
switch (sio.CtrlReg&0x2002) {
case 0x0002:
if (!PAD1setSlot(1, 1+sio.activePadSlot[0])) {
// Pad is not present. Don't send poll, just return a bunch of 0's.
sio2.packet.recvVal1 = 0x1D100;
sio.padst = 3;
}
else {
sio.buf[0] = PAD1startPoll(1);
}
break;
case 0x2002:
if (!PAD2setSlot(1, 1+sio.activePadSlot[1])) {
// Pad is not present. Don't send poll, just return a bunch of 0's.
sio2.packet.recvVal1 = 0x1D100;
sio.padst = 3;
}
else {
sio.buf[0] = PAD2startPoll(2);
}
break;
}
SIO_INT();
return;
@ -465,7 +559,35 @@ void InitializeSIO(u8 value)
sio.packetsize = 1;
sio.mtapst = 1;
sio.count = 0;
sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :)
sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :(
switch (sio.CtrlReg&0x2002) {
case 0x0002:
if (!IsMtapPresent(1)) {
// If "unplug" multitap, set slots to 0.
sio.activePadSlot[0] = 0;
sio.activeMemcardSlot[0] = 0;
break;
}
sio.bufcount = 3;
sio.buf[0] = 0xFF;
sio.buf[1] = 0x80;
sio.buf[2] = 0x5A;
sio2.packet.recvVal1 = 0x1100; // Mtap is connected :)
break;
case 0x2002:
if (!IsMtapPresent(2)) {
// If "unplug" multitap, set slots to 0.
sio.activePadSlot[1] = 0;
sio.activeMemcardSlot[1] = 0;
break;
}
sio.bufcount = 3;
sio.buf[0] = 0xFF;
sio.buf[1] = 0x80;
sio.buf[2] = 0x5A;
sio2.packet.recvVal1 = 0x1100; // Mtap is connected :)
break;
}
SIO_INT();
return;
@ -492,7 +614,7 @@ void InitializeSIO(u8 value)
sio.count = 0;
// Memcard presence reporting!
// In addition to checking the presence of MemoryCard1/2 file handles, we check a
// In addition to checking the presence of MemoryCard1/2 file handles, we check a
// variable which force-disables all memory cards after a savestate recovery. This
// is needed to inform certain games to clear their cached memorycard indexes.
@ -502,7 +624,12 @@ void InitializeSIO(u8 value)
const int mcidx = sio.GetMemcardIndex();
if( m_PostSavestateCards[mcidx] )
if( sio.activeMemcardSlot[mcidx] )
{
sio2.packet.recvVal1 = 0x1D100;
PAD_LOG( "START MEMCARD[%d][%d] - Only one memcard supported per slot - reported as missing.", sio.GetMemcardIndex(), sio.activeMemcardSlot[mcidx]);
}
else if( m_PostSavestateCards[mcidx] )
{
m_PostSavestateCards[mcidx]--;
sio2.packet.recvVal1 = 0x1D100;
@ -567,7 +694,14 @@ void SaveState::sioFreeze()
u64 m_mcdCRCs[2];
FreezeTag( "sio" );
Freeze( sio );
if (GetVersion() == 0) {
FreezeMem( &sio, sizeof( sio ) - 4);
memset(sio.activePadSlot, 0, sizeof(sio.activePadSlot));
memset(sio.activeMemcardSlot, 0, sizeof(sio.activeMemcardSlot));
}
else {
Freeze( sio );
}
if( IsSaving() )
{
@ -581,15 +715,15 @@ void SaveState::sioFreeze()
// Note: TOTA works with values as low as 20 here.
// It "times out" with values around 1800 (forces user to check the memcard
// twice to find it). Other games could be different. :|
// At 64: Disgaea 1 and 2, and Grandia 2 end up displaying a quick "no memcard!"
// notice before finding the memorycard and re-enumerating it. A very minor
// annoyance, but no breakages.
// GuitarHero will break completely with almost any value here, by design, because
// it has a "rule" that the memcard should never be ejected during a song. So by
// ejecting it, the game freezes (which is actually good emulation, but annoying!)
for( int i=0; i<2; ++i )
{
u64 newCRC = MemoryCard::GetCRC( i );

View File

@ -61,6 +61,11 @@ struct _sio {
u32 k;
u32 count;
// Active pad slot for each port. Not sure if these automatically reset after each read or not.
u8 activePadSlot[2];
// Active memcard slot for each port. Not sure if these automatically reset after each read or not.
u8 activeMemcardSlot[2];
int GetMemcardIndex() const
{
return (CtrlReg&0x2000) >> 13;