IOS/NCD: Implement Lock/Unlock more accurately

NCD returns an error if it receives a request to lock the driver
when it is already locked.

Emulating this may seem pointless, but it turns out PPC-side code
expects NCD to return an error and will immediately fail and stop
initialising wireless stuff if NCD succeeds.
This commit is contained in:
Léo Lam 2020-11-29 00:58:33 +01:00
parent 3f68aceaca
commit 4fea832f49
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
3 changed files with 51 additions and 2 deletions

View File

@ -20,6 +20,12 @@ NetNCDManage::NetNCDManage(Kernel& ios, const std::string& device_name) : Device
config.ReadConfig(ios.GetFS().get()); config.ReadConfig(ios.GetFS().get());
} }
void NetNCDManage::DoState(PointerWrap& p)
{
Device::DoState(p);
p.Do(m_ipc_fd);
}
IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request) IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request)
{ {
s32 return_value = IPC_SUCCESS; s32 return_value = IPC_SUCCESS;
@ -29,11 +35,51 @@ IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request)
switch (request.request) switch (request.request)
{ {
case IOCTLV_NCD_LOCKWIRELESSDRIVER: case IOCTLV_NCD_LOCKWIRELESSDRIVER:
if (!request.HasNumberOfValidVectors(0, 1))
return GetDefaultReply(IPC_EINVAL);
if (request.io_vectors[0].size < 2 * sizeof(u32))
return GetDefaultReply(IPC_EINVAL);
if (m_ipc_fd != 0)
{
// It is an error to lock the driver again when it is already locked.
common_result = IPC_EINVAL;
}
else
{
// NCD writes the internal address of the request's file descriptor.
// We will just write the value of the file descriptor.
// The value will be positive so this will work fine.
m_ipc_fd = request.fd;
Memory::Write_U32(request.fd, request.io_vectors[0].address + 4);
}
break; break;
case IOCTLV_NCD_UNLOCKWIRELESSDRIVER: case IOCTLV_NCD_UNLOCKWIRELESSDRIVER:
// Memory::Read_U32(request.in_vectors.at(0).address); {
if (!request.HasNumberOfValidVectors(1, 1))
return GetDefaultReply(IPC_EINVAL);
if (request.in_vectors[0].size < sizeof(u32))
return GetDefaultReply(IPC_EINVAL);
if (request.io_vectors[0].size < sizeof(u32))
return GetDefaultReply(IPC_EINVAL);
const u32 request_handle = Memory::Read_U32(request.in_vectors[0].address);
if (m_ipc_fd == request_handle)
{
m_ipc_fd = 0;
common_result = 0;
}
else
{
common_result = -3;
}
break; break;
}
case IOCTLV_NCD_GETCONFIG: case IOCTLV_NCD_GETCONFIG:
INFO_LOG_FMT(IOS_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETCONFIG"); INFO_LOG_FMT(IOS_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETCONFIG");

View File

@ -20,6 +20,8 @@ public:
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
void DoState(PointerWrap& p) override;
private: private:
enum enum
{ {
@ -34,5 +36,6 @@ private:
}; };
Net::WiiNetConfig config; Net::WiiNetConfig config;
u32 m_ipc_fd = 0;
}; };
} // namespace IOS::HLE::Device } // namespace IOS::HLE::Device

View File

@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 126; // Last changed in PR 9348 constexpr u32 STATE_VERSION = 127; // Last changed in PR 9300 (temp)
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,