* Re-implemented memorycard ejection (yay!) -- helps avoid memorycard corruption when using savestates on many games (due to them caching memorycard contents).

* Memorycard settings are now applied on-the-fly (can add/remove/disable memory cards in the BIOS browser and it'll act just as if you plugged or unplugged cards on a real PS2)
* Bugfixed memorycard creation dialog; which wasn't creating the memorycards in the right place (oops).

* Removed the CWD option from the first time wizard (was redundant since adding the custom location option).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3081 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-05-26 01:57:08 +00:00
parent 9708f279e0
commit 24e70bd524
20 changed files with 194 additions and 73 deletions

View File

@ -450,7 +450,7 @@ typedef struct _PS2E_VersionInfo
// PS2E_SessionInfo
// --------------------------------------------------------------------------------------
// This struct is populated by the emulator prior to starting emulation, and is passed to
// each plugin via a call to PS2E_PluginLibAPI::EmuStart().
// each plugin via a call to PS2E_PluginLibAPI::EmuOpen().
//
typedef struct _PS2E_SessionInfo
{
@ -649,7 +649,7 @@ typedef struct _PS2E_FreezeData
//
typedef struct _PS2E_ComponentAPI
{
// EmuStart
// EmuOpen
// This function is called by the emulator when an emulation session is started. The
// plugin should take this opportunity to bind itself to the given window handle, open
// necessary audio/video/input devices, etc.
@ -658,14 +658,14 @@ typedef struct _PS2E_ComponentAPI
// session - provides relevant emulation session information. Provided pointer is
// valid until after the subsequent call to EmuClose()
//
// Threading: EmuStart is called from the GUI thread. All other emulation threads are
// Threading: EmuOpen is called from the GUI thread. All other emulation threads are
// guaranteed to be suspended or closed at the time of this call (no locks required).
//
void (PS2E_CALLBACK* EmuStart)( PS2E_THISPTR thisptr, const PS2E_SessionInfo *session );
void (PS2E_CALLBACK* EmuOpen)( PS2E_THISPTR thisptr, const PS2E_SessionInfo *session );
// EmuClose
// This function is called by the emulator prior to stopping emulation. The window
// handle specified in EmuStart is guaranteed to be valid at the time EmuClose is called,
// handle specified in EmuOpen is guaranteed to be valid at the time EmuClose is called,
// and the plugin should unload/unbind all window dependencies at this time.
//
// Threading: EmuClose is called from the GUI thread. All other emulation threads are
@ -691,7 +691,7 @@ typedef struct _PS2E_ComponentAPI
// This function should make a complete copy of the plugin's emulation state into the
// provided dest->Data pointer. The plugin is allowed to reduce the dest->Size value
// but is not allowed to make it larger. The plugin will only receive calls to Freeze
// and Thaw while a plugin is in an EmuStart() state.
// and Thaw while a plugin is in an EmuOpen() state.
//
// Parameters:
// dest - a pointer to the Data/Size destination buffer (never NULL).
@ -704,7 +704,7 @@ typedef struct _PS2E_ComponentAPI
// Thaw
// Plugin should restore a complete emulation state from the given FreezeData. The
// plugin will only receive calls to Freeze and Thaw while a plugin is in an EmuStart()
// plugin will only receive calls to Freeze and Thaw while a plugin is in an EmuOpen()
// state.
//
// Thread Safety:
@ -719,10 +719,10 @@ typedef struct _PS2E_ComponentAPI
// this plugin is grayed out.
//
// All emulation is suspended and the plugin's state is saved to memory prior to this
// function being called. Configure is only called outside the context of EmuStart()
// function being called. Configure is only called outside the context of EmuOpen()
// (after a call to EmuClose()).
//
// Plugin authors should ensure to re-read and re-apply all settings on EmuStart(),
// Plugin authors should ensure to re-read and re-apply all settings on EmuOpen(),
// which will ensure that any user changes will be applied immediately. For changes
// that can be applied without emulation suspension, see/use the GUI extensions for
// menu and toolbar shortcuts.

View File

@ -23,6 +23,8 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEvt_SynchronousCommand, -1 )
END_DECLARE_EVENT_TYPES()
typedef void FnType_Void();
// --------------------------------------------------------------------------------------
// SynchronousActionState
// --------------------------------------------------------------------------------------

View File

@ -41,8 +41,6 @@ public:
virtual void OnActionButtonClicked( wxCommandEvent& evt );
};
typedef void FnType_Void();
typedef std::list<wxEvent*> wxEventList;
// --------------------------------------------------------------------------------------

View File

@ -1020,6 +1020,17 @@ bool PluginManager::OpenPlugin_FW()
return true;
}
bool PluginManager::OpenPlugin_Mcd()
{
ScopedLock lock( m_mtx_PluginStatus );
// [TODO] Fix up and implement PS2E_SessionInfo here!! (the currently NULL parameter)
if( SysPlugins.Mcd )
SysPlugins.Mcd->Base.EmuOpen( (PS2E_THISPTR) SysPlugins.Mcd, NULL );
return true;
}
void PluginManager::Open( PluginsEnum_t pid )
{
pxAssume( (uint)pid < PluginId_Count );
@ -1039,6 +1050,7 @@ void PluginManager::Open( PluginsEnum_t pid )
case PluginId_USB: result = OpenPlugin_USB(); break;
case PluginId_FW: result = OpenPlugin_FW(); break;
case PluginId_DEV9: result = OpenPlugin_DEV9(); break;
jNO_DEFAULT;
}
if( !result )
@ -1068,6 +1080,12 @@ void PluginManager::Open()
if (GSopen2) GetMTGS().WaitForOpen();
if( !AtomicExchange( m_mcdOpen, true ) )
{
DbgCon.Indent().WriteLn( "Opening Memorycards");
OpenPlugin_Mcd();
}
Console.WriteLn( Color_StrongBlue, "Plugins opened successfully." );
}
@ -1120,6 +1138,11 @@ void PluginManager::ClosePlugin_FW()
_generalclose( PluginId_FW );
}
void PluginManager::ClosePlugin_Mcd()
{
ScopedLock lock( m_mtx_PluginStatus );
if( SysPlugins.Mcd ) SysPlugins.Mcd->Base.EmuClose( (PS2E_THISPTR) SysPlugins.Mcd );
}
void PluginManager::Close( PluginsEnum_t pid )
{
@ -1139,6 +1162,7 @@ void PluginManager::Close( PluginsEnum_t pid )
case PluginId_USB: ClosePlugin_USB(); break;
case PluginId_FW: ClosePlugin_FW(); break;
case PluginId_DEV9: ClosePlugin_DEV9(); break;
case PluginId_Mcd: ClosePlugin_Mcd(); break;
jNO_DEFAULT;
}
@ -1156,6 +1180,12 @@ void PluginManager::Close()
DbgCon.WriteLn( Color_StrongBlue, "Closing plugins..." );
if( AtomicExchange( m_mcdOpen, false ) )
{
DbgCon.Indent().WriteLn( "Closing Memorycards");
ClosePlugin_Mcd();
}
for( int i=PluginId_Count-1; i>=0; --i )
Close( tbl_PluginInfo[i].id );

View File

@ -268,6 +268,9 @@ protected:
wxString m_SettingsFolder;
Threading::MutexRecursive m_mtx_PluginStatus;
// Lovely hack until the new PS2E API is completed.
volatile u32 m_mcdOpen;
public: // hack until we unsuck plugins...
ScopedPtr<PluginStatus_t> m_info[PluginId_Count];
@ -327,6 +330,7 @@ protected:
virtual bool OpenPlugin_DEV9();
virtual bool OpenPlugin_USB();
virtual bool OpenPlugin_FW();
virtual bool OpenPlugin_Mcd();
void _generalclose( PluginsEnum_t pid );
@ -337,6 +341,7 @@ protected:
virtual void ClosePlugin_DEV9();
virtual void ClosePlugin_USB();
virtual void ClosePlugin_FW();
virtual void ClosePlugin_Mcd();
friend class SysMtgsThread;
};

View File

@ -26,7 +26,9 @@ static const u8 cardh[4] = { 0xFF, 0xFF, 0x5a, 0x5d };
// Memory Card Specs : Sector size etc.
static const mc_command_0x26_tag mc_command_0x26= {'+', 512, 16, 0x4000, 0x52, 0x5A};
static int m_PostSavestateCards[2] = { 0, 0 };
// Ejection timeout management belongs in the MemoryCardFile plugin, except the plugin
// interface is not yet complete.
static int m_ForceEjectionTimeout[2];
// SIO Inline'd IRQs : Calls the SIO interrupt handlers directly instead of
// feeding them through the IOP's branch test. (see SIO.H for details)
@ -88,7 +90,7 @@ static u8 sio_xor( const u8 *buf, uint length )
void sioInit()
{
memzero(sio);
memzero(m_PostSavestateCards);
memzero(m_ForceEjectionTimeout);
// Transfer(?) Ready and the Buffer is Empty
sio.StatReg = TX_RDY | TX_EMPTY;
@ -602,7 +604,18 @@ void InitializeSIO(u8 value)
const uint port = sio.GetMemcardIndex();
const uint slot = sio.activeMemcardSlot[port];
if( SysPlugins.McdIsPresent( port, slot ) )
// forced ejection logic. Technically belongs in the McdIsPresent handler for
// the plugin, once the memorycard plugin system is completed.
// (ejection is only supported for the default non-multitap cards at this time)
bool forceEject = false;
if( slot == 0 && m_ForceEjectionTimeout[port] )
{
--m_ForceEjectionTimeout[port];
forceEject = true;
}
if( !forceEject && SysPlugins.McdIsPresent( port, slot ) )
{
sio2.packet.recvVal1 = 0x1100;
PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
@ -654,19 +667,29 @@ void SaveStateBase::sioFreeze()
FreezeTag( "sio" );
Freeze( sio );
// TODO : This stuff should all be moved to the memorycard plugin eventually,
// but that requires adding memorycard plugin to the savestate, and I'm not in
// the mood to do that (let's plan it for 0.9.8) --air
// Note: The Ejection system only works for the default non-multitap MemoryCards
// only. This is because it could become very (very!) slow to do a full CRC check
// on multiple 32 or 64 meg carts. I have chosen to save
if( IsSaving() )
{
for( int port=0; port<2; ++port )
for( uint port=0; port<2; ++port )
//for( uint slot=0; slot<4; ++slot )
{
for( int slot=0; slot<4; ++slot )
const int slot = 0; // see above comment about multitap slowness
m_mcdCRCs[port][slot] = SysPlugins.McdGetCRC( port, slot );
}
}
Freeze( m_mcdCRCs );
if( IsLoading() && EmuConfig.McdEnableEjection )
{
// Notes:
// Notes on the ForceEjectionTimeout:
// * 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. :|
@ -680,14 +703,14 @@ void SaveStateBase::sioFreeze()
// ejecting it, the game freezes (which is actually good emulation, but annoying!)
for( int port=0; port<2; ++port )
//for( int slot=0; slot<4; ++slot )
{
for( int slot=0; slot<4; ++slot )
{
const int slot = 0; // see above comment about multitap slowness
u64 newCRC = SysPlugins.McdGetCRC( port, slot );
if( newCRC != m_mcdCRCs[port][slot] )
{
m_mcdCRCs[port][slot] = newCRC;
}
//m_mcdCRCs[port][slot] = newCRC;
m_ForceEjectionTimeout[port] = 128;
}
}
}

View File

@ -100,7 +100,7 @@ namespace PathDefs
switch( mode )
{
case DocsFolder_User: return (wxDirName)Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() );
case DocsFolder_CWD: return (wxDirName)wxGetCwd();
//case DocsFolder_CWD: return (wxDirName)wxGetCwd();
case DocsFolder_Custom: return CustomDocumentsFolder;
jNO_DEFAULT
@ -561,7 +561,7 @@ void AppConfig::FolderOptions::LoadSave( IniInterface& ini )
{
ApplyDefaults();
if( DocsFolderMode != DocsFolder_CWD )
//if( DocsFolderMode != DocsFolder_CWD )
{
for( int i=0; i<FolderId_COUNT; ++i )
operator[]( (FoldersEnum_t)i ).Normalize();
@ -719,7 +719,7 @@ void RelocateLogfile()
//
void AppConfig_OnChangedSettingsFolder( bool overwrite )
{
if( DocsFolderMode != DocsFolder_CWD )
//if( DocsFolderMode != DocsFolder_CWD )
PathDefs::GetDocuments().Mkdir();
GetSettingsFolder().Mkdir();

View File

@ -25,7 +25,7 @@ enum DocsModeType
DocsFolder_User,
// uses the current working directory for program data
DocsFolder_CWD,
//DocsFolder_CWD,
// uses a custom location for program data
DocsFolder_Custom,

View File

@ -500,8 +500,10 @@ void SysExecEvent_SaveSinglePlugin::InvokeEvent()
s_DisableGsWindow = true; // keeps the GS window smooth by avoiding closing the window
ScopedCoreThreadPause paused_core;
_LoadPluginsImmediate();
//_LoadPluginsImmediate();
if( CorePlugins.AreLoaded() )
{
ScopedPtr<VmStateBuffer> plugstore;
if( CoreThread.HasActiveMachine() )
@ -521,6 +523,7 @@ void SysExecEvent_SaveSinglePlugin::InvokeEvent()
GetCorePlugins().Freeze( m_pid, load );
GetCorePlugins().Close( m_pid ); // hack for stupid GS plugins.
}
}
s_DisableGsWindow = false;
paused_core.AllowResume();

View File

@ -16,6 +16,8 @@
#pragma once
#include "System/SysThreads.h"
#include "pxEventThread.h"
#include "AppCommon.h"
#include "AppCorePlugins.h"
#include "SaveState.h"

View File

@ -170,13 +170,16 @@ void Dialogs::BaseConfigurationDialog::OnSetSettingsPage( wxCommandEvent& evt )
}
}
void Dialogs::BaseConfigurationDialog::SomethingChanged()
{
if( wxWindow* apply = FindWindow( wxID_APPLY ) ) apply->Enable();
}
void Dialogs::BaseConfigurationDialog::OnSomethingChanged( wxCommandEvent& evt )
{
evt.Skip();
if( (evt.GetId() != wxID_OK) && (evt.GetId() != wxID_CANCEL) && (evt.GetId() != wxID_APPLY) )
{
if( wxWindow* apply = FindWindow( wxID_APPLY ) ) apply->Enable();
}
SomethingChanged();
}

View File

@ -55,6 +55,8 @@ namespace Dialogs
void AddListbook( wxSizer* sizer=NULL );
void CreateListbook( wxImageList& bookicons );
virtual void SomethingChanged();
template< typename T >
void AddPage( const char* label, int iconid );
@ -68,8 +70,8 @@ namespace Dialogs
void OnCloseWindow( wxCloseEvent& evt );
void OnSetSettingsPage( wxCommandEvent& evt );
void OnSomethingChanged( wxCommandEvent& evt );
virtual void OnSomethingChanged( wxCommandEvent& evt );
virtual wxString& GetConfSettingsTabName() const=0;
};

View File

@ -73,13 +73,14 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint
s_padding += m_filepicker | StdExpand();
else
{
s_padding += Heading( _( "(new card will be saved to:" ) );
s_padding += Heading( _( "New card will be saved to:" ) );
s_padding += Heading( (m_mcdpath + m_mcdfile).GetFullPath() );
}
s_padding += m_radio_CardSize | StdExpand();
#ifdef __WXMSW__
if( m_check_CompressNTFS ) s_padding += m_check_CompressNTFS | StdExpand();
if( m_check_CompressNTFS )
s_padding += m_check_CompressNTFS | StdExpand();
#endif
s_padding += 12;
@ -87,8 +88,6 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint
*this += s_padding | StdExpand();
//FindItem( wxID_OK )->SetLabel(_("Create"));
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CreateMemoryCardDialog::OnOk_Click ) );
//Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CreateMemoryCardDialog::OnApply_Click ) );
}
@ -126,7 +125,7 @@ static bool CreateIt( const wxString& mcdFile, uint sizeInMB )
void Dialogs::CreateMemoryCardDialog::OnOk_Click( wxCommandEvent& evt )
{
if( !CreateIt(
m_filepicker ? m_filepicker->GetPath() : m_mcdfile,
m_filepicker ? m_filepicker->GetPath() : (m_mcdpath + m_mcdfile).GetFullPath(),
m_radio_CardSize ? m_radio_CardSize->SelectedItem().SomeInt : 8
) )
{

View File

@ -172,6 +172,9 @@ Dialogs::McdConfigDialog::McdConfigDialog( wxWindow* parent )
//AddPage<McdConfigPanel_Toggles> ( wxLt("Settings"), cfgid.MemoryCard );
//AddPage<McdConfigPanel_Standard> ( wxLt("Slots 1/2"), cfgid.MemoryCard );
*this += Heading(_("Drag items in the list over other items to swap or copy MemoryCards."));
*this += StdPadding;
*this += m_panel_mcdlist | StdExpand();
//*this += StdPadding;
*this += new wxStaticLine( this ) | StdExpand();

View File

@ -58,6 +58,9 @@ public:
void Lock();
void Unlock();
void Open();
void Close();
s32 IsPresent ( uint slot );
s32 Read ( uint slot, u8 *dest, u32 adr, int size );
s32 Save ( uint slot, const u8 *src, u32 adr, int size );
@ -132,17 +135,44 @@ wxString FileMcd_GetDefaultName(uint slot)
FileMemoryCard::FileMemoryCard()
{
memset8<0xff>( m_effeffs );
}
void FileMemoryCard::Open()
{
for( int slot=0; slot<8; ++slot )
{
if( !g_Conf->Mcd[slot].Enabled || g_Conf->Mcd[slot].Filename.GetFullName().IsEmpty() ) continue;
if( FileMcd_IsMultitapSlot(slot) )
{
if( !EmuConfig.MultitapPort0_Enabled && (FileMcd_GetMtapPort(slot) == 0) ) continue;
if( !EmuConfig.MultitapPort1_Enabled && (FileMcd_GetMtapPort(slot) == 1) ) continue;
}
wxFileName fname( g_Conf->FullpathToMcd( slot ) );
wxString str( fname.GetFullPath() );
bool cont = false;
if( fname.GetFullName().IsEmpty() )
{
str = L"[empty filename]";
cont = true;
}
if( !g_Conf->Mcd[slot].Enabled )
{
str = L"[disabled]";
cont = true;
}
Console.WriteLn( cont ? Color_Gray : Color_Green, L"McdSlot %u: " + str, slot );
if( cont ) continue;
const wxULongLong fsz = fname.GetSize();
if( (fsz == 0) || (fsz == wxInvalidSize) )
{
// FIXME : Ideally this should prompt the user for the size of the
// memorycard file they would like to create, instead of trying to
// create one automatically.
if( !Create( str, 8 ) )
{
Msgbox::Alert(
@ -153,7 +183,7 @@ FileMemoryCard::FileMemoryCard()
}
// [TODO] : Add memcard size detection and report it to the console log.
// (8MB, 256Mb, whatever)
// (8MB, 256Mb, formatted, unformatted, etc ...)
#ifdef __WXMSW__
NTFS_CompressFile( str, g_Conf->McdCompressNTFS );
@ -171,6 +201,12 @@ FileMemoryCard::FileMemoryCard()
}
}
void FileMemoryCard::Close()
{
for( int slot=0; slot<8; ++slot )
m_file[slot].Close();
}
// Returns FALSE if the seek failed (is outside the bounds of the file).
bool FileMemoryCard::Seek( wxFFile& f, u32 adr )
{
@ -308,6 +344,16 @@ uint FileMcd_ConvertToSlot( uint port, uint slot )
return slot + 4; // multitap 2
}
static void PS2E_CALLBACK FileMcd_EmuOpen( PS2E_THISPTR thisptr, const PS2E_SessionInfo *session )
{
thisptr->impl.Open();
}
static void PS2E_CALLBACK FileMcd_EmuClose( PS2E_THISPTR thisptr )
{
thisptr->impl.Close();
}
static s32 PS2E_CALLBACK FileMcd_IsPresent( PS2E_THISPTR thisptr, uint port, uint slot )
{
return thisptr->impl.IsPresent( FileMcd_ConvertToSlot( port, slot ) );
@ -337,6 +383,9 @@ Component_FileMcd::Component_FileMcd()
{
memzero( api );
api.Base.EmuOpen = FileMcd_EmuOpen;
api.Base.EmuClose = FileMcd_EmuClose;
api.McdIsPresent = FileMcd_IsPresent;
api.McdRead = FileMcd_Read;
api.McdSave = FileMcd_Save;

View File

@ -69,6 +69,7 @@ void Panels::BaseSelectorPanel::RefreshSelections()
void Panels::BaseSelectorPanel::OnRefreshSelections( wxCommandEvent& evt )
{
evt.Skip();
RefreshSelections();
}

View File

@ -14,9 +14,11 @@
*/
#include "PrecompiledHeader.h"
#include "AppCoreThread.h"
#include "System.h"
#include "ConfigurationPanels.h"
#include "MemoryCardPanels.h"
#include "System.h"
#include <wx/filepicker.h>
#include <wx/ffile.h>
@ -491,6 +493,9 @@ void Panels::MemoryCardListPanel_Simple::Apply()
{
//_parent::Apply();
ScopedCoreThreadClose closed_core;
closed_core.AllowResume();
for( uint slot=0; slot<8; ++slot )
{
g_Conf->Mcd[slot].Enabled = m_Cards[slot].IsEnabled && m_Cards[slot].IsPresent;
@ -581,6 +586,8 @@ void Panels::MemoryCardListPanel_Simple::OnCreateCard(wxCommandEvent& evt)
void Panels::MemoryCardListPanel_Simple::OnMountCard(wxCommandEvent& evt)
{
evt.Skip();
const int sel = m_listview->GetFirstSelected();
if( wxNOT_FOUND == sel ) return;
const uint slot = sel;

View File

@ -51,12 +51,6 @@ Panels::DocsFolderPickerPanel::DocsFolderPickerPanel( wxWindow* parent, bool isF
_("Location: ") + wxStandardPaths::Get().GetDocumentsDir()
),
RadioPanelItem(
_("Current working folder (intended for developer use only)"),
_("Location: ") + wxGetCwd(),
_("This setting requires administration privileges from your operating system.")
),
RadioPanelItem(
_("Custom folder:"),
wxEmptyString,

View File

@ -672,7 +672,7 @@ void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
else if( m_ComponentBoxes->Get(pid).GetSelection() == wxNOT_FOUND )
{
m_ComponentBoxes->Get(pid).SetSelection( 0 );
m_ComponentBoxes->GetConfigButton(pid).Enable( CorePlugins.AreLoaded() );
m_ComponentBoxes->GetConfigButton(pid).Enable( !CorePlugins.AreLoaded() );
}
} while( ++pi, pi->shortname != NULL );