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

@ -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];
@ -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;
}

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

@ -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);
}
@ -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
@ -412,19 +430,42 @@ void SIO_CommandWrite(u8 value,int way) {
return;
}
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,6 +473,40 @@ 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;
@ -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" );
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() )
{

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;