mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Usb: Implement state waits.
See #11067 - implementing in hopes of reducing spin.
This commit is contained in:
parent
5d62610a93
commit
cfbeadccc7
@ -50,11 +50,10 @@
|
||||
#include "Core/HLE/KernelWaitHelpers.h"
|
||||
#include "Core/HLE/ThreadQueueList.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct WaitTypeNames {
|
||||
WaitType type;
|
||||
const char *name;
|
||||
} WaitTypeNames;
|
||||
};
|
||||
|
||||
const WaitTypeNames waitTypeNames[] = {
|
||||
{ WAITTYPE_NONE, "None" },
|
||||
@ -83,18 +82,13 @@ const WaitTypeNames waitTypeNames[] = {
|
||||
{ WAITTYPE_ASYNCIO, "AsyncIO" },
|
||||
{ WAITTYPE_MICINPUT, "Microphone input"},
|
||||
{ WAITTYPE_NET, "Network"},
|
||||
{ WAITTYPE_USB, "USB" },
|
||||
};
|
||||
|
||||
const char *getWaitTypeName(WaitType type)
|
||||
{
|
||||
int waitTypeNamesAmount = sizeof(waitTypeNames)/sizeof(WaitTypeNames);
|
||||
|
||||
for (int i = 0; i < waitTypeNamesAmount; i++)
|
||||
{
|
||||
if (waitTypeNames[i].type == type)
|
||||
{
|
||||
return waitTypeNames[i].name;
|
||||
}
|
||||
const char *getWaitTypeName(WaitType type) {
|
||||
for (WaitTypeNames info : waitTypeNames) {
|
||||
if (info.type == type)
|
||||
return info.name;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
|
@ -110,6 +110,7 @@ enum WaitType : int
|
||||
WAITTYPE_ASYNCIO = 23,
|
||||
WAITTYPE_MICINPUT = 24, // fake
|
||||
WAITTYPE_NET = 25, // fake
|
||||
WAITTYPE_USB = 26, // fake
|
||||
|
||||
NUM_WAITTYPES
|
||||
};
|
||||
|
@ -17,18 +17,26 @@
|
||||
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/FunctionWrappers.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HLE/KernelWaitHelpers.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceUsb.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
static constexpr uint32_t ERROR_USB_WAIT_TIMEOUT = 0x80243008;
|
||||
|
||||
// TODO: Map by driver name
|
||||
bool usbStarted = false;
|
||||
static bool usbStarted = false;
|
||||
// TODO: Check actual status
|
||||
bool usbConnected = true;
|
||||
static bool usbConnected = true;
|
||||
// TODO: Activation by product id
|
||||
bool usbActivated = false;
|
||||
static bool usbActivated = false;
|
||||
|
||||
static int usbWaitTimer = -1;
|
||||
static std::vector<SceUID> waitingThreads;
|
||||
|
||||
enum UsbStatus {
|
||||
USB_STATUS_STOPPED = 0x001,
|
||||
@ -39,16 +47,85 @@ enum UsbStatus {
|
||||
USB_STATUS_ACTIVATED = 0x200,
|
||||
};
|
||||
|
||||
void __UsbInit()
|
||||
{
|
||||
static int UsbCurrentState() {
|
||||
int state = 0;
|
||||
if (usbStarted) {
|
||||
state = USB_STATUS_STARTED
|
||||
| (usbConnected ? USB_STATUS_CONNECTED : USB_STATUS_DISCONNECTED)
|
||||
| (usbActivated ? USB_STATUS_ACTIVATED : USB_STATUS_DEACTIVATED);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool UsbMatchState(int state, u32 mode) {
|
||||
int match = state & UsbCurrentState();
|
||||
if (mode == 0) {
|
||||
return match == state;
|
||||
}
|
||||
return match != 0;
|
||||
}
|
||||
|
||||
static void UsbSetTimeout(PSPPointer<int> timeout) {
|
||||
if (!timeout.IsValid() || usbWaitTimer == -1)
|
||||
return;
|
||||
|
||||
// This should call __UsbWaitTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(*timeout), usbWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
static void UsbWaitExecTimeout(u64 userdata, int cycleslate) {
|
||||
u32 error;
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
PSPPointer<int> timeout = PSPPointer<int>::Create(__KernelGetWaitTimeoutPtr(threadID, error));
|
||||
if (timeout.IsValid())
|
||||
*timeout = 0;
|
||||
|
||||
HLEKernel::RemoveWaitingThread(waitingThreads, threadID);
|
||||
__KernelResumeThreadFromWait(threadID, ERROR_USB_WAIT_TIMEOUT);
|
||||
__KernelReSchedule("wait timed out");
|
||||
}
|
||||
|
||||
static void UsbUpdateState() {
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (size_t i = 0; i < waitingThreads.size(); ++i) {
|
||||
SceUID threadID = waitingThreads[i];
|
||||
int state = __KernelGetWaitID(threadID, WAITTYPE_USB, error);
|
||||
if (error != 0)
|
||||
continue;
|
||||
|
||||
u32 mode = __KernelGetWaitValue(threadID, error);
|
||||
if (UsbMatchState(state, mode)) {
|
||||
waitingThreads.erase(waitingThreads.begin() + i);
|
||||
--i;
|
||||
|
||||
PSPPointer<int> timeout = PSPPointer<int>::Create(__KernelGetWaitTimeoutPtr(threadID, error));
|
||||
if (timeout.IsValid() && usbWaitTimer != -1) {
|
||||
// Remove any event for this thread.
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(usbWaitTimer, threadID);
|
||||
*timeout = (int)cyclesToUs(cyclesLeft);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, UsbCurrentState());
|
||||
}
|
||||
}
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("usb state change");
|
||||
}
|
||||
|
||||
void __UsbInit() {
|
||||
usbStarted = false;
|
||||
usbConnected = true;
|
||||
usbActivated = false;
|
||||
waitingThreads.clear();
|
||||
|
||||
usbWaitTimer = CoreTiming::RegisterEvent("UsbWaitTimeout", UsbWaitExecTimeout);
|
||||
}
|
||||
|
||||
void __UsbDoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("sceUsb", 1, 2);
|
||||
void __UsbDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceUsb", 1, 3);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@ -60,17 +137,27 @@ void __UsbDoState(PointerWrap &p)
|
||||
usbConnected = true;
|
||||
}
|
||||
Do(p, usbActivated);
|
||||
if (s >= 3) {
|
||||
Do(p, waitingThreads);
|
||||
Do(p, usbWaitTimer);
|
||||
} else {
|
||||
waitingThreads.clear();
|
||||
usbWaitTimer = -1;
|
||||
}
|
||||
CoreTiming::RestoreRegisterEvent(usbWaitTimer, "UsbWaitTimeout", UsbWaitExecTimeout);
|
||||
}
|
||||
|
||||
static int sceUsbStart(const char* driverName, u32 argsSize, u32 argsPtr) {
|
||||
INFO_LOG(HLE, "sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr);
|
||||
usbStarted = true;
|
||||
UsbUpdateState();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbStop(const char* driverName, u32 argsSize, u32 argsPtr) {
|
||||
INFO_LOG(HLE, "sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr);
|
||||
usbStarted = false;
|
||||
UsbUpdateState();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -79,9 +166,7 @@ static int sceUsbGetState() {
|
||||
if (!usbStarted) {
|
||||
state = 0x80243007;
|
||||
} else {
|
||||
state = USB_STATUS_STARTED
|
||||
| (usbConnected ? USB_STATUS_CONNECTED : USB_STATUS_DISCONNECTED)
|
||||
| (usbActivated ? USB_STATUS_ACTIVATED : USB_STATUS_DEACTIVATED);
|
||||
state = UsbCurrentState();
|
||||
}
|
||||
DEBUG_LOG(HLE, "sceUsbGetState: 0x%x", state);
|
||||
return state;
|
||||
@ -90,22 +175,40 @@ static int sceUsbGetState() {
|
||||
static int sceUsbActivate(u32 pid) {
|
||||
INFO_LOG(HLE, "sceUsbActivate(%i)", pid);
|
||||
usbActivated = true;
|
||||
UsbUpdateState();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbDeactivate(u32 pid) {
|
||||
INFO_LOG(HLE, "sceUsbDeactivate(%i)", pid);
|
||||
usbActivated = false;
|
||||
UsbUpdateState();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbWaitState(int state, int waitMode, u32 timeoutAddr) {
|
||||
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStat(%i, %i, %08x)", state, waitMode, timeoutAddr);
|
||||
return sceUsbGetState();
|
||||
static int sceUsbWaitState(int state, u32 waitMode, u32 timeoutPtr) {
|
||||
hleEatCycles(10000);
|
||||
|
||||
if (waitMode >= 2)
|
||||
return hleLogError(HLE, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode");
|
||||
if (state == 0)
|
||||
return hleLogError(HLE, SCE_KERNEL_ERROR_EVF_ILPAT, "bad state");
|
||||
|
||||
if (UsbMatchState(state, waitMode)) {
|
||||
return hleLogSuccessX(HLE, UsbCurrentState());
|
||||
}
|
||||
|
||||
// We'll have to wait as long as it takes. Cleanup first, just in case.
|
||||
HLEKernel::RemoveWaitingThread(waitingThreads, __KernelGetCurThread());
|
||||
waitingThreads.push_back(__KernelGetCurThread());
|
||||
|
||||
UsbSetTimeout(PSPPointer<int>::Create(timeoutPtr));
|
||||
__KernelWaitCurThread(WAITTYPE_USB, state, waitMode, timeoutPtr, false, "usb state waited");
|
||||
return hleLogSuccessI(HLE, 0, "waiting");
|
||||
}
|
||||
|
||||
static int sceUsbWaitStateCB(int state, int waitMode, u32 timeoutAddr) {
|
||||
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutAddr);
|
||||
static int sceUsbWaitStateCB(int state, u32 waitMode, u32 timeoutPtr) {
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -118,8 +221,8 @@ const HLEFunction sceUsb[] =
|
||||
{0X112CC951, nullptr, "sceUsbGetDrvState", '?', "" },
|
||||
{0X586DB82C, &WrapI_U<sceUsbActivate>, "sceUsbActivate", 'i', "x" },
|
||||
{0XC572A9C8, &WrapI_U<sceUsbDeactivate>, "sceUsbDeactivate", 'i', "x" },
|
||||
{0X5BE0E002, &WrapI_IIU<sceUsbWaitState>, "sceUsbWaitState", '?', "xxx"},
|
||||
{0X616F2B61, &WrapI_IIU<sceUsbWaitStateCB>, "sceUsbWaitStateCB", '?', "xxx"},
|
||||
{0X5BE0E002, &WrapI_IUU<sceUsbWaitState>, "sceUsbWaitState", 'x', "xip"},
|
||||
{0X616F2B61, &WrapI_IUU<sceUsbWaitStateCB>, "sceUsbWaitStateCB", 'x', "xip"},
|
||||
{0X1C360735, nullptr, "sceUsbWaitCancel", '?', "" },
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user