2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
#include "HLE.h"
|
|
|
|
#include "../MIPS/MIPS.h"
|
2012-11-26 05:44:01 +00:00
|
|
|
#include "../CoreTiming.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#include "StdMutex.h"
|
|
|
|
#include "sceCtrl.h"
|
2012-12-02 23:44:23 +00:00
|
|
|
#include "sceDisplay.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
/* Index for the two analog directions */
|
|
|
|
#define CTRL_ANALOG_X 0
|
|
|
|
#define CTRL_ANALOG_Y 1
|
|
|
|
|
2012-11-11 23:09:27 +00:00
|
|
|
#define CTRL_MODE_DIGITAL 0
|
|
|
|
#define CTRL_MODE_ANALOG 1
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
const int PSP_CTRL_ERROR_INVALID_MODE = 0x80000107;
|
2012-11-26 05:44:01 +00:00
|
|
|
const int PSP_CTRL_ERROR_INVALID_NUM_BUFFERS = 0x80000104;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// Returned control data
|
|
|
|
struct _ctrl_data
|
|
|
|
{
|
|
|
|
u32 frame;
|
|
|
|
u32 buttons;
|
|
|
|
u8 analog[2];
|
|
|
|
u8 unused[6];
|
|
|
|
};
|
|
|
|
|
2012-11-08 15:28:45 +00:00
|
|
|
struct CtrlLatch {
|
|
|
|
u32 btnMake;
|
|
|
|
u32 btnBreak;
|
|
|
|
u32 btnPress;
|
|
|
|
u32 btnRelease;
|
|
|
|
};
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// STATE BEGIN
|
|
|
|
static bool ctrlInited = false;
|
|
|
|
static bool analogEnabled = false;
|
2012-11-26 06:10:25 +00:00
|
|
|
static int ctrlLatchBufs = 0;
|
|
|
|
static u32 ctrlOldButtons = 0;
|
2012-11-09 18:04:57 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
static _ctrl_data ctrlBufs[64];
|
|
|
|
static _ctrl_data ctrlCurrent;
|
|
|
|
static int ctrlBuf = 0;
|
|
|
|
static int ctrlBufRead = 0;
|
2012-11-09 18:04:57 +00:00
|
|
|
static CtrlLatch latch;
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
static std::recursive_mutex ctrlMutex;
|
2012-11-09 18:04:57 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
// STATE END
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
2012-11-26 06:10:25 +00:00
|
|
|
void __CtrlUpdateLatch()
|
2012-11-26 04:59:52 +00:00
|
|
|
{
|
2012-11-26 06:10:25 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
u32 changed = ctrlCurrent.buttons ^ ctrlOldButtons;
|
|
|
|
latch.btnMake |= ctrlCurrent.buttons & changed;
|
2012-11-26 06:10:25 +00:00
|
|
|
latch.btnBreak |= ctrlOldButtons & changed;
|
2012-12-02 23:44:23 +00:00
|
|
|
latch.btnPress |= ctrlCurrent.buttons;
|
|
|
|
latch.btnRelease |= (ctrlOldButtons & ~ctrlCurrent.buttons) & changed;
|
2012-11-26 06:10:25 +00:00
|
|
|
ctrlLatchBufs++;
|
2012-11-09 18:04:57 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
ctrlOldButtons = ctrlCurrent.buttons;
|
|
|
|
|
|
|
|
// Copy in the current data to the current buffer.
|
|
|
|
memcpy(&ctrlBufs[ctrlBuf], &ctrlCurrent, sizeof(_ctrl_data));
|
|
|
|
|
|
|
|
ctrlBufs[ctrlBuf].frame = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz());
|
|
|
|
if (!analogEnabled)
|
|
|
|
{
|
|
|
|
ctrlBufs[ctrlBuf].analog[0] = 128;
|
|
|
|
ctrlBufs[ctrlBuf].analog[1] = 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrlBuf = (ctrlBuf + 1) % 64;
|
|
|
|
|
|
|
|
// If we wrapped around, push the read head forward.
|
|
|
|
// TODO: Is this right?
|
|
|
|
if (ctrlBufRead == ctrlBuf)
|
|
|
|
ctrlBufRead = (ctrlBufRead + 1) % 64;
|
2012-11-09 18:04:57 +00:00
|
|
|
}
|
|
|
|
|
2012-11-26 06:10:25 +00:00
|
|
|
int __CtrlResetLatch()
|
|
|
|
{
|
|
|
|
int oldBufs = ctrlLatchBufs;
|
|
|
|
memset(&latch, 0, sizeof(CtrlLatch));
|
|
|
|
ctrlLatchBufs = 0;
|
|
|
|
return oldBufs;
|
|
|
|
}
|
2012-11-18 16:51:14 +00:00
|
|
|
|
|
|
|
u32 __CtrlPeekButtons()
|
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
return ctrlCurrent.buttons;
|
2012-11-18 16:51:14 +00:00
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
// Functions so that the rest of the emulator can control what the sceCtrl interface should return
|
|
|
|
// to the game:
|
|
|
|
|
|
|
|
void __CtrlButtonDown(u32 buttonBit)
|
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
2012-12-02 23:44:23 +00:00
|
|
|
ctrlCurrent.buttons |= buttonBit;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void __CtrlButtonUp(u32 buttonBit)
|
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
2012-12-02 23:44:23 +00:00
|
|
|
ctrlCurrent.buttons &= ~buttonBit;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void __CtrlSetAnalog(float x, float y)
|
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
|
|
|
// TODO: Circle!
|
|
|
|
if (x > 1.0f) x = 1.0f;
|
|
|
|
if (y > 1.0f) y = 1.0f;
|
|
|
|
if (x < -1.0f) x = -1.0f;
|
|
|
|
if (y < -1.0f) y = -1.0f;
|
2012-12-02 23:44:23 +00:00
|
|
|
ctrlCurrent.analog[0] = (u8)(x * 127.f + 128.f);
|
|
|
|
ctrlCurrent.analog[1] = (u8)(y * 127.f + 128.f);
|
|
|
|
}
|
2012-11-26 06:10:25 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
void __CtrlVblank()
|
|
|
|
{
|
|
|
|
// When in vblank sampling mode, this samples the ctrl data into the buffers and updates the latch.
|
2012-11-26 06:10:25 +00:00
|
|
|
__CtrlUpdateLatch();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
void __CtrlInit()
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
if (!ctrlInited)
|
|
|
|
{
|
|
|
|
__DisplayListenVblank(__CtrlVblank);
|
|
|
|
ctrlInited = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrlBuf = 0;
|
|
|
|
ctrlBufRead = 0;
|
|
|
|
ctrlOldButtons = 0;
|
|
|
|
ctrlLatchBufs = 0;
|
|
|
|
|
2012-11-26 06:10:25 +00:00
|
|
|
memset(&latch, 0, sizeof(latch));
|
2012-12-02 20:44:33 +00:00
|
|
|
// Start with everything released.
|
|
|
|
latch.btnRelease = 0xffffffff;
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
memset(&ctrlCurrent, 0, sizeof(ctrlCurrent));
|
|
|
|
memset(&ctrlBufs, 0, sizeof(ctrlBufs));
|
|
|
|
ctrlCurrent.analog[0] = 128;
|
|
|
|
ctrlCurrent.analog[1] = 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sceCtrlInit()
|
|
|
|
{
|
|
|
|
__CtrlInit();
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-11-07 18:10:52 +00:00
|
|
|
DEBUG_LOG(HLE,"sceCtrlInit");
|
2012-11-17 18:56:28 +00:00
|
|
|
RETURN(0);
|
|
|
|
}
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
u32 sceCtrlSetSamplingCycle(u32 cycle)
|
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
if (cycle == 0)
|
|
|
|
{
|
|
|
|
// TODO: Change to vblank when we support something else.
|
|
|
|
DEBUG_LOG(HLE, "sceCtrlSetSamplingCycle(%u)", cycle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceCtrlSetSamplingCycle(%u)", cycle);
|
|
|
|
}
|
2012-11-26 04:59:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceCtrlGetSamplingCycle(u32 cyclePtr)
|
|
|
|
{
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceCtrlSetSamplingCycle(%08x)", cyclePtr);
|
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-11-11 23:09:27 +00:00
|
|
|
u32 sceCtrlSetSamplingMode(u32 mode)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-11 23:09:27 +00:00
|
|
|
u32 retVal = 0;
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
DEBUG_LOG(HLE, "sceCtrlSetSamplingMode(%i)", mode);
|
|
|
|
if (mode > 1)
|
|
|
|
return PSP_CTRL_ERROR_INVALID_MODE;
|
2012-11-11 23:09:27 +00:00
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
|
|
|
analogEnabled = mode == CTRL_MODE_ANALOG ? true : false;
|
2012-11-11 23:09:27 +00:00
|
|
|
return retVal;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
int sceCtrlGetSamplingMode(u32 modePtr)
|
|
|
|
{
|
|
|
|
u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
|
|
|
|
|
|
|
if (Memory::IsValidAddress(modePtr))
|
|
|
|
Memory::Write_U32(retVal, modePtr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-05 09:05:09 +00:00
|
|
|
void sceCtrlSetIdleCancelThreshold()
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
DEBUG_LOG(HLE,"UNIMPL sceCtrlSetIdleCancelThreshold");
|
2012-11-17 18:56:28 +00:00
|
|
|
RETURN(0);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-26 05:44:01 +00:00
|
|
|
if (nBufs > 64)
|
|
|
|
return PSP_CTRL_ERROR_INVALID_NUM_BUFFERS;
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
int resetRead = ctrlBufRead;
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
int done = 0;
|
|
|
|
_ctrl_data data;
|
|
|
|
for (u32 i = 0; i < nBufs; ++i)
|
2012-11-26 04:59:52 +00:00
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
// Ran out of buffers.
|
|
|
|
if (ctrlBuf == ctrlBufRead)
|
|
|
|
break;
|
2012-11-26 05:44:01 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
if (Memory::IsValidAddress(ctrlDataPtr))
|
2012-11-26 04:59:52 +00:00
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
memcpy(&data, &ctrlBufs[ctrlBufRead], sizeof(_ctrl_data));
|
|
|
|
ctrlBufRead = (ctrlBufRead + 1) % 64;
|
|
|
|
|
|
|
|
if (negative)
|
|
|
|
data.buttons = ~data.buttons;
|
|
|
|
|
|
|
|
Memory::WriteStruct(ctrlDataPtr, &data);
|
|
|
|
done++;
|
2012-11-26 04:59:52 +00:00
|
|
|
}
|
2012-12-02 23:44:23 +00:00
|
|
|
ctrlDataPtr += sizeof(_ctrl_data);
|
2012-11-26 04:59:52 +00:00
|
|
|
}
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
if (peek)
|
|
|
|
ctrlBufRead = resetRead;
|
|
|
|
|
|
|
|
return done;
|
2012-11-26 04:59:52 +00:00
|
|
|
}
|
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
void sceCtrlReadBufferPositive(u32 ctrlDataPtr, u32 nBufs)
|
2012-11-26 04:59:52 +00:00
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
// TODO: Wait for vblank if there are 0 buffers (resched.)
|
|
|
|
DEBUG_LOG(HLE,"sceCtrlReadBufferPositive(%08x, %i)", ctrlDataPtr, nBufs);
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
RETURN(__CtrlReadBuffer(ctrlDataPtr, nBufs, false, false));
|
|
|
|
}
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
void sceCtrlReadBufferNegative(u32 ctrlDataPtr, u32 nBufs)
|
|
|
|
{
|
|
|
|
// TODO: Wait for vblank if there are 0 buffers (resched.)
|
|
|
|
DEBUG_LOG(HLE,"sceCtrlReadBufferNegative(%08x, %i)", ctrlDataPtr, nBufs);
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
RETURN(__CtrlReadBuffer(ctrlDataPtr, nBufs, true, false));
|
|
|
|
}
|
2012-11-26 05:44:01 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
int sceCtrlPeekBufferPositive(u32 ctrlDataPtr, u32 nBufs)
|
|
|
|
{
|
|
|
|
DEBUG_LOG(HLE,"sceCtrlPeekBufferPositive(%08x, %i)", ctrlDataPtr, nBufs);
|
|
|
|
return __CtrlReadBuffer(ctrlDataPtr, nBufs, false, true);
|
|
|
|
}
|
2012-11-26 04:59:52 +00:00
|
|
|
|
2012-12-02 23:44:23 +00:00
|
|
|
int sceCtrlPeekBufferNegative(u32 ctrlDataPtr, u32 nBufs)
|
|
|
|
{
|
|
|
|
DEBUG_LOG(HLE,"sceCtrlPeekBufferNegative(%08x, %i)", ctrlDataPtr, nBufs);
|
|
|
|
return __CtrlReadBuffer(ctrlDataPtr, nBufs, true, true);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
u32 sceCtrlPeekLatch(u32 latchDataPtr)
|
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
ERROR_LOG(HLE, "sceCtrlPeekLatch(%08x)", latchDataPtr);
|
2012-11-26 06:10:25 +00:00
|
|
|
|
2012-11-09 18:04:57 +00:00
|
|
|
if (Memory::IsValidAddress(latchDataPtr))
|
|
|
|
Memory::WriteStruct(latchDataPtr, &latch);
|
2012-12-02 23:44:23 +00:00
|
|
|
|
2012-11-26 06:10:25 +00:00
|
|
|
return ctrlLatchBufs;
|
2012-11-08 15:28:45 +00:00
|
|
|
}
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
u32 sceCtrlReadLatch(u32 latchDataPtr)
|
|
|
|
{
|
2012-12-02 23:44:23 +00:00
|
|
|
ERROR_LOG(HLE, "sceCtrlReadLatch(%08x)", latchDataPtr);
|
2012-11-09 18:04:57 +00:00
|
|
|
|
|
|
|
if (Memory::IsValidAddress(latchDataPtr))
|
|
|
|
Memory::WriteStruct(latchDataPtr, &latch);
|
2012-11-08 15:28:45 +00:00
|
|
|
|
2012-11-26 06:10:25 +00:00
|
|
|
return __CtrlResetLatch();
|
2012-11-08 15:28:45 +00:00
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
static const HLEFunction sceCtrl[] =
|
|
|
|
{
|
2012-11-26 04:59:52 +00:00
|
|
|
{0x3E65A0EA, WrapV_V<sceCtrlInit>, "sceCtrlInit"}, //(int unknown), init with 0
|
|
|
|
{0x1f4011e6, WrapU_U<sceCtrlSetSamplingMode>, "sceCtrlSetSamplingMode"}, //(int on);
|
|
|
|
{0x6A2774F3, WrapU_U<sceCtrlSetSamplingCycle>, "sceCtrlSetSamplingCycle"},
|
|
|
|
{0x02BAAD91, WrapI_U<sceCtrlGetSamplingCycle>,"sceCtrlGetSamplingCycle"},
|
|
|
|
{0xDA6B76A1, WrapI_U<sceCtrlGetSamplingMode>, "sceCtrlGetSamplingMode"},
|
2012-12-02 23:44:23 +00:00
|
|
|
{0x1f803938, WrapV_UU<sceCtrlReadBufferPositive>, "sceCtrlReadBufferPositive"}, //(ctrl_data_t* paddata, int unknown) // unknown should be 1
|
|
|
|
{0x3A622550, WrapI_UU<sceCtrlPeekBufferPositive>, "sceCtrlPeekBufferPositive"},
|
|
|
|
{0xC152080A, WrapI_UU<sceCtrlPeekBufferNegative>, "sceCtrlPeekBufferNegative"},
|
|
|
|
{0x60B81F86, WrapV_UU<sceCtrlReadBufferNegative>, "sceCtrlReadBufferNegative"},
|
2012-11-26 04:59:52 +00:00
|
|
|
{0xB1D0E5CD, WrapU_U<sceCtrlPeekLatch>, "sceCtrlPeekLatch"},
|
|
|
|
{0x0B588501, WrapU_U<sceCtrlReadLatch>, "sceCtrlReadLatch"},
|
|
|
|
{0x348D99D4, 0, "sceCtrl_348D99D4"},
|
|
|
|
{0xAF5960F3, 0, "sceCtrl_AF5960F3"},
|
|
|
|
{0xA68FD260, 0, "sceCtrlClearRapidFire"},
|
|
|
|
{0x6841BE1A, 0, "sceCtrlSetRapidFire"},
|
|
|
|
{0xa7144800, WrapV_V<sceCtrlSetIdleCancelThreshold>, "sceCtrlSetIdleCancelThreshold"},
|
|
|
|
{0x687660fa, 0, "sceCtrlGetIdleCancelThreshold"},
|
2012-11-01 15:19:01 +00:00
|
|
|
};
|
|
|
|
|
2012-11-26 04:59:52 +00:00
|
|
|
void Register_sceCtrl()
|
|
|
|
{
|
|
|
|
RegisterModule("sceCtrl", ARRAY_SIZE(sceCtrl), sceCtrl);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|