Skip to content

Commit 30b8488

Browse files
committed
Parallel card/hosts, attempt 1
1 parent b1b01a5 commit 30b8488

File tree

10 files changed

+128
-71
lines changed

10 files changed

+128
-71
lines changed

pcsx2/SIO/Memcard/Memcard.cpp

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "SIO/Memcard/MemcardPS2.h"
88
#include "SIO/Memcard/MemcardPS1.h"
99
#include "SIO/Memcard/MemcardNotConnected.h"
10+
#include "SIO/Memcard/MemcardHostBase.h"
1011
#include "SIO/Memcard/MemcardHostFile.h"
1112
#include "SIO/Memcard/MemcardHostFolder.h"
1213

@@ -17,6 +18,7 @@
1718

1819
namespace Memcard
1920
{
21+
static std::array<std::unique_ptr<MemcardHostBase>, Memcard::MAX_SLOTS> s_memcardHosts;
2022
static std::array<std::unique_ptr<MemcardBase>, Memcard::MAX_SLOTS> s_memcards;
2123
} // namespace Memcard
2224

@@ -29,28 +31,41 @@ bool Memcard::Initialize()
2931
if (fileName.empty())
3032
{
3133
s_memcards.at(i) = std::make_unique<MemcardNotConnected>(i);
34+
s_memcardHosts.at(i) = nullptr;
3235
}
3336
else
3437
{
3538
const std::string fullPath = Path::Combine(EmuFolders::MemoryCards, fileName);
3639

37-
if (fullPath.ends_with(".ps2"))
40+
// First, determine if the host is a file or folder, and set up a host object for it.
41+
if (FileSystem::FileExists(fullPath.c_str()))
3842
{
39-
s_memcards.at(i) = std::make_unique<MemcardPS2>(i, fullPath);
43+
s_memcardHosts.at(i) = std::make_unique<MemcardHostFile>(fullPath);
4044
}
41-
else if (fullPath.ends_with(".mcd"))
45+
else if (FileSystem::DirectoryExists(fullPath.c_str()))
4246
{
43-
s_memcards.at(i) = std::make_unique<MemcardPS1>(i, fullPath);
47+
s_memcardHosts.at(i) = std::make_unique<MemcardHostFolder>(fullPath);
48+
}
49+
else
50+
{
51+
s_memcardHosts.at(i) = nullptr;
52+
s_memcards.at(i) = std::make_unique<MemcardNotConnected>(i);
53+
54+
Host::ReportFormattedErrorAsync("Memory Card",
55+
"Memory card not found: \n\n%s\n\n"
56+
"PCSX2 will treat this memory card as ejected for this session.",
57+
fullPath.c_str()
58+
);
59+
60+
continue;
4461
}
4562

46-
// If a host was not built because no such file or folder existed,
47-
// or a file card failed to open, then ditch the card
48-
if (!s_memcards.at(i)->GetHost() || !s_memcards.at(i)->GetHost()->IsOpened())
63+
// If the host failed to open, then ditch the card
64+
if (!s_memcardHosts.at(i)->IsOpened())
4965
{
66+
s_memcardHosts.at(i) = nullptr;
5067
s_memcards.at(i) = std::make_unique<MemcardNotConnected>(i);
5168

52-
// Translation note: detailed description should mention that the memory card will be disabled
53-
// for the duration of this session.
5469
Host::ReportFormattedErrorAsync("Memory Card",
5570
"Access denied to memory card: \n\n%s\n\n"
5671
"PCSX2 will treat this memory card as ejected for this session. Another instance of PCSX2 may be using this memory card. Close any other instances of PCSX2, or restart your computer.%s",
@@ -61,6 +76,48 @@ bool Memcard::Initialize()
6176
""
6277
#endif
6378
);
79+
80+
continue;
81+
}
82+
83+
// Now that we know the host is fine, determine what type of emulated memory card we are creating.
84+
if (fullPath.ends_with(".ps2"))
85+
{
86+
s_memcards.at(i) = std::make_unique<MemcardPS2>(i);
87+
}
88+
else if (fullPath.ends_with(".mcd"))
89+
{
90+
s_memcards.at(i) = std::make_unique<MemcardPS1>(i);
91+
}
92+
else
93+
{
94+
s_memcardHosts.at(i) = nullptr;
95+
s_memcards.at(i) = std::make_unique<MemcardNotConnected>(i);
96+
97+
Host::ReportFormattedErrorAsync("Memory Card",
98+
"Unrecognized file extension: \n\n%s\n\n"
99+
"Please check your memory card settings and insert a valid memory card.",
100+
fullPath.c_str()
101+
);
102+
103+
continue;
104+
}
105+
106+
// Validate that the capacity is okay for the type of emulated card
107+
MemcardBase* memcard = s_memcards.at(i).get();
108+
109+
if (!memcard->ValidateCapacity())
110+
{
111+
s_memcardHosts.at(i) = nullptr;
112+
s_memcards.at(i) = std::make_unique<MemcardNotConnected>(i);
113+
114+
Host::ReportFormattedErrorAsync("Memory Card",
115+
"Malformed memory card: \n\n%s\n\n"
116+
"File size does not match a known memory card size. Please check your memory card settings and insert a valid memory card.",
117+
fullPath.c_str()
118+
);
119+
120+
continue;
64121
}
65122
}
66123
}
@@ -78,11 +135,22 @@ void Memcard::Shutdown()
78135

79136
MemcardBase* Memcard::GetMemcard(const u32 unifiedSlot)
80137
{
81-
return s_memcards[unifiedSlot].get();
138+
return s_memcards.at(unifiedSlot).get();
82139
}
83140

84141
MemcardBase* Memcard::GetMemcard(const u32 port, const u32 slot)
85142
{
86143
const u32 unifiedSlot = sioConvertPortAndSlotToPad(port, slot);
87-
return s_memcards[unifiedSlot].get();
144+
return s_memcards.at(unifiedSlot).get();
145+
}
146+
147+
MemcardHostBase* Memcard::GetMemcardHost(const u32 unifiedSlot)
148+
{
149+
return s_memcardHosts.at(unifiedSlot).get();
150+
}
151+
152+
MemcardHostBase* Memcard::GetMemcardHost(const u32 port, const u32 slot)
153+
{
154+
const u32 unifiedSlot = sioConvertPortAndSlotToPad(port, slot);
155+
return s_memcardHosts.at(unifiedSlot).get();
88156
}

pcsx2/SIO/Memcard/Memcard.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,6 @@ namespace Memcard
5555

5656
MemcardBase* GetMemcard(const u32 unifiedSlot);
5757
MemcardBase* GetMemcard(const u32 port, const u32 slot);
58+
MemcardHostBase* GetMemcardHost(const u32 unifiedSlot);
59+
MemcardHostBase* GetMemcardHost(const u32 port, const u32 slot);
5860
} // namespace Memcard

pcsx2/SIO/Memcard/MemcardBase.cpp

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,11 @@
1212
#include "fmt/core.h"
1313
#include "IconsFontAwesome5.h"
1414

15-
MemcardBase::MemcardBase(u32 unifiedSlot, std::string fullPath)
15+
MemcardBase::MemcardBase(u32 unifiedSlot)
1616
{
1717
this->unifiedSlot = unifiedSlot;
1818
this->autoEjectTicks = 0;
1919
this->lastWriteTime = std::chrono::system_clock::now();
20-
21-
if (fullPath == "")
22-
{
23-
return;
24-
}
25-
else if (FileSystem::FileExists(fullPath.c_str()))
26-
{
27-
this->hostType = Memcard::HostType::FILE;
28-
this->memcardHost = std::make_unique<MemcardHostFile>(fullPath);
29-
}
30-
else if (FileSystem::DirectoryExists(fullPath.c_str()))
31-
{
32-
this->hostType = Memcard::HostType::FOLDER;
33-
this->memcardHost = std::make_unique<MemcardHostFolder>(fullPath);
34-
}
3520
}
3621

3722
MemcardBase::~MemcardBase() = default;
@@ -41,11 +26,6 @@ u32 MemcardBase::GetUnifiedSlot()
4126
return this->unifiedSlot;
4227
}
4328

44-
MemcardHostBase* MemcardBase::GetHost()
45-
{
46-
return this->memcardHost.get();
47-
}
48-
4929
void MemcardBase::SendWriteMessageToHost()
5030
{
5131
const std::chrono::duration<float> elapsed = std::chrono::system_clock::now() - this->lastWriteTime;
@@ -59,7 +39,7 @@ void MemcardBase::SendWriteMessageToHost()
5939
ICON_FA_SD_CARD,
6040
fmt::format(
6141
TRANSLATE_FS("MemoryCard", "Memory Card '{}' written to storage."),
62-
Path::GetFileName(this->memcardHost->GetPath())),
42+
Path::GetFileName(this->GetMemcardHost()->GetPath())),
6343
Host::OSD_INFO_DURATION);
6444
this->lastWriteTime = std::chrono::system_clock::now();
6545
}
@@ -74,3 +54,8 @@ void MemcardBase::SetAutoEject()
7454
{
7555
this->autoEjectTicks = 100;
7656
}
57+
58+
MemcardHostBase* MemcardBase::GetMemcardHost()
59+
{
60+
return Memcard::GetMemcardHost(this->unifiedSlot);
61+
}

pcsx2/SIO/Memcard/MemcardBase.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,27 @@
22
#pragma once
33

44
#include "SIO/Memcard/Memcard.h"
5-
#include "SIO/Memcard/MemcardHostBase.h"
65

76
class MemcardBase
87
{
98
private:
109
u32 unifiedSlot;
1110

1211
protected:
13-
Memcard::HostType hostType;
14-
std::unique_ptr<MemcardHostBase> memcardHost;
1512
u32 autoEjectTicks;
1613
std::chrono::time_point<std::chrono::system_clock> lastWriteTime;
1714

1815
public:
19-
MemcardBase(u32 unifiedSlot, std::string fullPath);
16+
MemcardBase(u32 unifiedSlot);
2017
virtual ~MemcardBase();
2118

2219
u32 GetUnifiedSlot();
23-
MemcardHostBase* GetHost();
2420
void SendWriteMessageToHost();
2521
u32 GetAutoEjectTicks();
2622
void SetAutoEject();
23+
MemcardHostBase* GetMemcardHost();
2724

2825
virtual Memcard::Type GetType() = 0;
26+
virtual bool ValidateCapacity() = 0;
2927
virtual void ExecuteCommand() = 0;
3028
};

pcsx2/SIO/Memcard/MemcardNotConnected.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "SIO/Sio0.h"
88

99
MemcardNotConnected::MemcardNotConnected(u32 unifiedSlot)
10-
: MemcardBase(unifiedSlot, "")
10+
: MemcardBase(unifiedSlot)
1111
{
1212

1313
}
@@ -18,6 +18,11 @@ Memcard::Type MemcardNotConnected::GetType()
1818
return Memcard::Type::NOT_CONNECTED;
1919
}
2020

21+
bool MemcardNotConnected::ValidateCapacity()
22+
{
23+
return true;
24+
}
25+
2126
// No-op. Let SIO2 and SIO0 sit with no response.
2227
void MemcardNotConnected::ExecuteCommand()
2328
{

pcsx2/SIO/Memcard/MemcardNotConnected.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ class MemcardNotConnected : public MemcardBase
1313
~MemcardNotConnected();
1414

1515
Memcard::Type GetType() override;
16+
bool ValidateCapacity() override;
1617
void ExecuteCommand() override;
1718
};

pcsx2/SIO/Memcard/MemcardPS1.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
#include "SIO/Memcard/MemcardPS1.h"
55

6-
MemcardPS1::MemcardPS1(u32 unifiedSlot, std::string fullPath)
7-
: MemcardBase(unifiedSlot, fullPath)
6+
MemcardPS1::MemcardPS1(u32 unifiedSlot)
7+
: MemcardBase(unifiedSlot)
88
{
99

1010
}

pcsx2/SIO/Memcard/MemcardPS1.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class MemcardPS1 : public MemcardBase
1111
Memcard::Command currentCommand = Memcard::Command::NOT_SET;
1212

1313
public:
14-
MemcardPS1(u32 unifiedSlot, std::string fullPath);
14+
MemcardPS1(u32 unifiedSlot);
1515
~MemcardPS1();
1616

1717
Memcard::Type GetType() override;

pcsx2/SIO/Memcard/MemcardPS2.cpp

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "PrecompiledHeader.h"
33

44
#include "SIO/Memcard/MemcardPS2.h"
5+
#include "SIO/Memcard/MemcardHostBase.h"
56

67
#include "SIO/Sio.h"
78
#include "SIO/Sio2.h"
@@ -144,7 +145,7 @@ void MemcardPS2::WriteData()
144145
g_Sio2FifoOut.push_back(0x00);
145146
}
146147

147-
this->memcardHost->Write(this->currentAddr, buf);
148+
this->GetMemcardHost()->Write(this->currentAddr, buf);
148149
g_Sio2FifoOut.push_back(checksum);
149150
g_Sio2FifoOut.push_back(this->terminator);
150151
this->currentAddr += writeLength;
@@ -158,7 +159,7 @@ void MemcardPS2::ReadData()
158159
g_Sio2FifoOut.push_back(0x2B);
159160
std::vector<u8> buf;
160161
buf.resize(readLength);
161-
this->memcardHost->Read(this->currentAddr, buf);
162+
this->GetMemcardHost()->Read(this->currentAddr, buf);
162163
u8 checksum = 0x00;
163164

164165
for (const u8 readByte : buf)
@@ -191,7 +192,7 @@ void MemcardPS2::EraseBlock()
191192
std::vector<u8> clearData;
192193
clearData.resize(MemcardPS2::ERASE_BLOCK_LENGTH);
193194
memset(clearData.data(), 0xFF, clearData.size());
194-
this->memcardHost->Write(this->currentAddr, clearData);
195+
this->GetMemcardHost()->Write(this->currentAddr, clearData);
195196
this->lastClearedEraseBlockAddr = this->currentAddr;
196197

197198
g_Sio2FifoOut.push_back(0x2B);
@@ -299,23 +300,29 @@ void MemcardPS2::AuthF7()
299300
g_Sio2FifoOut.push_back(this->terminator);
300301
}
301302

302-
MemcardPS2::MemcardPS2(u32 unifiedSlot, std::string fullPath)
303-
: MemcardBase(unifiedSlot, fullPath)
303+
MemcardPS2::MemcardPS2(u32 unifiedSlot)
304+
: MemcardBase(unifiedSlot)
304305
{
305-
const s64 standardFileSize = (static_cast<u32>(ClusterCount::x8MB) * MemcardPS2::PAGES_PER_CLUSTER) * (MemcardPS2::PAGE_LENGTH + ECC_LENGTH);
306-
const s64 maxFileSize = (static_cast<u32>(ClusterCount::x2048MB) * MemcardPS2::PAGES_PER_CLUSTER) * (MemcardPS2::PAGE_LENGTH + ECC_LENGTH);
306+
this->clusterCount = static_cast<ClusterCount>(this->GetMemcardHost()->GetSize() / (MemcardPS2::PAGE_LENGTH + ECC_LENGTH) / MemcardPS2::PAGES_PER_CLUSTER);
307+
}
308+
309+
MemcardPS2::~MemcardPS2() = default;
310+
311+
Memcard::Type MemcardPS2::GetType()
312+
{
313+
return Memcard::Type::PS2;
314+
}
315+
316+
bool MemcardPS2::ValidateCapacity()
317+
{
318+
const u32 standardFileSize = (static_cast<u32>(ClusterCount::x8MB) * MemcardPS2::PAGES_PER_CLUSTER) * (MemcardPS2::PAGE_LENGTH + ECC_LENGTH);
319+
const u32 maxFileSize = (static_cast<u32>(ClusterCount::x2048MB) * MemcardPS2::PAGES_PER_CLUSTER) * (MemcardPS2::PAGE_LENGTH + ECC_LENGTH);
307320

308-
if (this->memcardHost)
321+
if (this->GetMemcardHost() != nullptr)
309322
{
310-
s64 fileSize = this->memcardHost->GetSize();
323+
const u32 fileSize = this->GetMemcardHost()->GetSize();
311324

312-
// If the host was a folder and reported -1, then we will have the card report 8 MB capacity to the PS2.
313-
if (fileSize < 0)
314-
{
315-
fileSize = standardFileSize;
316-
}
317-
// If the host was a file, verify that its size hasn't been tampered with.
318-
else if (fileSize > 0)
325+
if (fileSize > 0)
319326
{
320327
u32 compareSize = standardFileSize;
321328
bool sizeMatches = false;
@@ -331,21 +338,11 @@ MemcardPS2::MemcardPS2(u32 unifiedSlot, std::string fullPath)
331338
compareSize *= 2;
332339
} while (compareSize <= maxFileSize);
333340

334-
if (!sizeMatches)
335-
{
336-
Console.Warning("%s Irregular memcard file size detected (%s)", __FUNCTION__, fullPath);
337-
}
341+
return sizeMatches;
338342
}
339-
340-
this->clusterCount = static_cast<ClusterCount>(fileSize / (MemcardPS2::PAGE_LENGTH + ECC_LENGTH) / MemcardPS2::PAGES_PER_CLUSTER);
341343
}
342-
}
343344

344-
MemcardPS2::~MemcardPS2() = default;
345-
346-
Memcard::Type MemcardPS2::GetType()
347-
{
348-
return Memcard::Type::PS2;
345+
return false;
349346
}
350347

351348
void MemcardPS2::ExecuteCommand()

0 commit comments

Comments
 (0)