Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
2147 lines (1866 sloc) 77.4 KB
/* Copyright (C) 2011 - 2015 The uOFW team
See the file COPYING for copying permission.
*/
/*
* uofw/src/ctrl/ctrl.c
*
* sceController_Service - a driver for the PSP's hardware buttons.
*
* The controller libraries (controller and controller_driver) main
* function is to notify an application of information that is output
* from the controller, such as button and analog stick information.
*
* The controller module consists of 64 internal button data buffers
* which can be read by the user in order to obtain data. These buffers
* are filled with the content of the PSP's hardware registers containing
* controller data. This data is transfered into the internal controller
* data buffers via the SYSCON microcontroller.
*
* By default communication with SYSCON takes place once per frame via
* the VBlank interrupt and updates the internal controller data buffers.
* The VBlank interrupt occurs approximately 60 times per second.
*
*/
#include <ctrl.h>
#include <display.h>
#include <interruptman.h>
#include <modulemgr.h>
#include <modulemgr_init.h>
#include <syscon.h>
#include <sysmem_kdebug.h>
#include <sysmem_kernel.h>
#include <sysmem_suspend_kernel.h>
#include <sysmem_sysclib.h>
#include <sysmem_sysevent.h>
#include <systimer.h>
#include <threadman_kernel.h>
SCE_MODULE_INFO(
"sceController_Service",
SCE_MODULE_KERNEL |
SCE_MODULE_ATTR_CANT_STOP | SCE_MODULE_ATTR_EXCLUSIVE_LOAD | SCE_MODULE_ATTR_EXCLUSIVE_START,
1, 1
);
SCE_MODULE_BOOTSTART("_sceCtrlModuleStart");
SCE_MODULE_REBOOT_BEFORE("_sceCtrlModuleRebootBefore");
SCE_SDK_VERSION(SDK_VERSION);
#define USER_MODE (0)
#define KERNEL_MODE (1)
#define SVALALIGN64(v) ((v) - (((((u32)((s32)(v) >> 31)) >> 26) + (v)) & 0xFFFFFFC0))
/*
* When the controller module's update event flag is set with this bit,
* we signal a finished update of the internal controller button data
* buffers
*/
#define UPDATE_INTERRUPT_EVENT_FLAG_ON (1)
/*
* The number of the controller module's internal controller button data
* buffers.
*/
#define CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS (64)
#define CTRL_MAX_INTERNAL_CONTROLLER_BUFFER (CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS - 1)
/* The center position of the analog stick on both axes. */
#define CTRL_ANALOG_PAD_CENTER_VALUE (0x80)
/* The minimum position of the analog stick on both axes. */
#define CTRL_ANALOG_PAD_MIN_VALUE (0)
/* The maximum position of the analog stick on both axes. */
#define CTRL_ANALOG_PAD_MAX_VALUE (0xFF)
/*
* The smallest offset from the analog stick's center position defining
* the guaranteed range (center position +/- this offset) the stick
* returns to when being released.
*/
#define CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN (37)
/*
* When the analog stick idle timer threshold data contains this value, the
* analog stick cannot cancel the idle timer despite being moved.
*/
#define CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER (129)
#define CTRL_MAX_EXTRA_SUSPEND_SAMPLES (300)
/*
* The minimum time in microseconds a custom update interval for the
* controller data buffers can be long.
*/
#define CTRL_BUFFER_UPDATE_MIN_CUSTOM_CYCLES (5555)
/*
* The maximum time in microseconds a custom update interval for the
* controller data buffers can be long.
*/
#define CTRL_BUFFER_UPDATE_MAX_CUSTOM_CYCLES (20000)
/*
* In case the target PSP has an SDK version smaller than or equal to
* this SDK version, the buffer update cycle value will be increased
* by one. This happens when the user sets an own update time.
*/
#define CTRL_BUF_UPDATE_INCREASE_CYCLE_SDK_VER (0x204FFFF)
/* The default start time of the controller module's alarm handler. */
#define CTRL_ALARM_START_TIME (700)
#define CTRL_SAMPLING_MODES (2)
#define CTRL_SAMPLING_MODE_MAX_MODE (CTRL_SAMPLING_MODES - 1)
/* The total number of different external input sources for the controller data. */
#define CTRL_NUM_EXTERNAL_INPUT_MODES (2)
/* The maximum number of button callbacks which can be registered. */
#define CTRL_BUTTON_CALLBACK_SLOTS (4)
#define CTRL_BUTTON_CALLBACK_MAX_SLOT (CTRL_BUTTON_CALLBACK_SLOTS - 1)
#define CTRL_DATA_EMULATION_SLOTS (4)
#define CTRL_DATA_EMULATION_MAX_SLOT (CTRL_DATA_EMULATION_SLOTS - 1)
/* The maximum number of rapid fire events which can be registered. */
#define CTRL_BUTTONS_RAPID_FIRE_SLOTS (16)
#define CTRL_BUTTONS_RAPID_FIRE_MAX_SLOT (CTRL_BUTTONS_RAPID_FIRE_SLOTS - 1)
/* Obtain the left apply time of a rapid fire event mode. */
#define RF_EVENT_GET_APPLY_TIME_LEFT(data) ((data) & 0x3F)
/* Obtain the event mode of a rapid fire event. */
#define RF_EVENT_GET_MODE(data) ((u32)(data) >> 6)
/*
* Set the event mode of a rapid fire event. One of
* ::SceCtrlRapidFireEventModes.
*/
#define RF_EVENT_SET_MODE(data) ((data) << 6)
/* Defines the buttons which can be read by User mode applications. */
#define CTRL_USER_MODE_BUTTONS_DEFAULT (SCE_CTRL_SELECT | SCE_CTRL_START | SCE_CTRL_UP | SCE_CTRL_RIGHT | \
SCE_CTRL_DOWN | SCE_CTRL_LEFT | SCE_CTRL_LTRIGGER | SCE_CTRL_RTRIGGER | \
SCE_CTRL_TRIANGLE | SCE_CTRL_CIRCLE | SCE_CTRL_CROSS | SCE_CTRL_SQUARE | \
SCE_CTRL_INTERCEPTED | SCE_CTRL_HOLD)
#define CTRL_USER_MODE_BUTTONS_EXTENDED (0x3FFFF)
/*
* The default button group which can cancel the PSP's idle timer every
* one of its buttons is pressed.
*/
#define CTRL_ALL_TIME_IDLE_TIMER_RESET_BUTTONS (SCE_CTRL_SELECT | SCE_CTRL_START | SCE_CTRL_UP | SCE_CTRL_RIGHT | \
SCE_CTRL_DOWN | SCE_CTRL_LEFT | SCE_CTRL_LTRIGGER | SCE_CTRL_RTRIGGER | \
SCE_CTRL_TRIANGLE | SCE_CTRL_CIRCLE | SCE_CTRL_CROSS | SCE_CTRL_SQUARE | \
SCE_CTRL_INTERCEPTED | SCE_CTRL_VOLUP | SCE_CTRL_VOLDOWN | SCE_CTRL_SCREEN | \
SCE_CTRL_NOTE)
#define CTRL_ALL_SUPPORTED_BUTTONS (0x39FFF3F9)
//SCE_CTRL_MS | SCE_CTRL_DISC | SCE_CTRL_REMOTE | SCE_CTRL_WLAN_UP | SCE_CTRL_HOLD | ?
#define CTRL_HARDWARE_IO_BUTTONS (0x3B0E0000)
/* Controller buffer read modes. */
enum SceCtrlReadBufferModes {
PEEK_BUFFER_POSITIVE = 0,
PEEK_BUFFER_NEGATIVE = 1,
READ_BUFFER_POSITIVE = 2,
READ_BUFFER_NEGATIVE = 3,
PEEK_BUFFER_POSITIVE_EXTRA = 4,
PEEK_BUFFER_NEGATIVE_EXTRA = 5,
READ_BUFFER_POSITIVE_EXTRA = 6,
READ_BUFFER_NEGATIVE_EXTRA = 7,
};
/* Defined rapid fire event modes. */
enum SceCtrlRapidFireEventModes {
/* The buttons belonging to a rapid fire event will be set to ON (they
* will show up as being pressed.
*/
RAPID_FIRE_EVENT_BUTTONS_ON = 2,
/* The buttons belonging to a rapid fire event will be set to OFF (they
* will show up as being un-pressed.
*/
RAPID_FIRE_EVENT_BUTTONS_OFF = 3,
};
/*
* This structure represents a rapid fire event for PSP buttons. A rapid
* fire event is a time period in which buttons are constantly turned ON and
* OFF without the user actually pressing the buttons.
*/
typedef struct {
/* Comparison mask of the button operation for rapid-fire trigger.
* This usage is restricted for now.
*/
u32 uiMask;
/* The buttons which will start the rapid fire event for the specified
* <uiTarget> buttons when being pressed.
*/
u32 uiTrigger;
/* The buttons on which the rapid fire event will be applied to. User
* mode buttons only.
*/
u32 uiTarget;
/*
* 7 6 5 0
* +------------+--------------+
* | EVENT MODE | APPLY TIME |
* +------------+--------------+
*
* Bit 7 - 6:
* The rapid fire event mode. Defines whether the button is turned
* ON or OFF. One of ::SceCtrlRapidFireEventModes.
*
* Bit 5 - 0:
* The remaining apply time for one event mode. The time is measured
* in the number of controller button data updates (and thus is a
* multiple of the update interval).
*/
u8 eventData;
/*
* Defines for how long the <uiTarget> buttons will act as being pressed. Meassured in sampling counts.
*/
u8 uiMake;
/*
* Defines for how long the <uiTarget> buttons will act as being unpressed. Meassured in sampling counts.
*/
u8 uiBreak;
/*
* Dead time of rapid-fire trigger (sampling count). Specifies the rapid-fire start timing.
*/
u8 uiDelay;
} SceCtrlRapidFire;
/*
* This structure represents emulation data applied to controller buffer
* button data. The emulation data is set by the user.
*/
typedef struct {
/* Emulated analog pad X-axis offset. */
u8 analogX;
/* Emulated analog pad Y-axis offset. */
u8 analogY;
/* The number of consecutive internal controller data buffer updates
* the emulated analog pad values will be applied.
*/
u32 uiAnalogMake;
/* Emulated user buttons of ::SceCtrlButtons. You cannot emulate
* kernel buttons and the emulated buttons will only be applied for
* applications running in User mode.
*/
u32 userButtons;
/* Emulated buttons of ::SceCtrlButtons (you can emulate both user
* and kernel buttons). The emulated buttons will only be applied
* for applications running in Kernel mode.
*/
u32 kernelButtons;
/* The number of consecutive internal controller data buffer updates
* the emulated buttons will be applied.
*/
u32 uiButtonMake;
} SceCtrlEmulationData;
/*
* This structure represents a button callback. A button callback is a
* function which is called when at least one of the specified callback
* buttons is pressed. The callback can be used to handle controller input
* without the need to obtain button data via functions like
* sceCtrlPeekBufferPositive().
*/
typedef struct {
/* Bitwise OR'ed buttons of ::SceCtrlButtons which will be checked
* for being pressed.
*/
u32 buttonMask;
/* Pointer to a callback function handling the controller input. */
SceKernelButtonCallbackFunction callback;
/* The global pointer value of the controller module. */
u32 gp;
/* An optional pointer being passed as the third argument to the
* callback function.
*/
void *arg;
} SceCtrlButtonCallback;
/*
* This structure represents an internal button data structure. An object
* of this structure is used to receive the transfered button data from
* SYSCON and fill the internal controller data buffers with that data.
* It also updates the internal latch data of the controller module
*/
typedef struct {
/* Button is newly pressed (it wasn't pressed one frame before the
* current one).
*/
u32 btnMake; // 0
/* Stop of button press. It was pressed one frame before the current
* one.
*/
u32 btnBreak; // 4
/* Button is pressed. */
u32 btnPress; // 8
/* Button is not pressed. */
u32 btnRelease; // 12
/* Count the internal latch buffer reads. Is set to 0 when the
* buffer is reset.
*/
u32 readLatchCount; // 16
/* Index representing the first updated controller button data buffer
* which wasn't read while containing the updated data before. Thus,
* if we have 13 updated buffers (from position 0 - 12), and this member
* is set to 10, the buffers at index 10, 11 and 12 are updated buffers
* which weren't read with the updated data before.
*/
u32 firstUnReadUpdatedBufIndex; // 20
/* The index describing the current buffer which will be updated the
* next time a SYSCON hardware button data transfer occurs.
*/
u32 curUpdatableBufIndex; // 24
/* An array of three pointers to 64 internal button data buffers
* containing controller information.
*/
void *pCtrlInputBuffers[3]; // 28
} SceCtrlInternalData;
/*
* The controller module's control block. Takes care of every important
* data of the controller.
*/
typedef struct {
/* The timer ID used for the custom update interval. */
s32 timerID;
/* Signals the end of an update interval of the controller button data
* buffers. Used in the context of sceCtrlReadBuffer* functions which
* need to wait for a finished update of the controller data buffers
* before obtaining data from them.
*/
s32 updateEventId;
/* The custom timing at which communication with SYSCON takes place.
* In case it is 0, the VBlank interrupt is used to define the update
* interval.
*/
u32 updateCycle;
/* The sampling modes of the internal controller button data buffers.
* samplingMode[0] = mode for User buffers, samplingMode[1] = mode for
* Kernel buffers. One of ::SceCtrlPadInputMode.
*/
u8 samplingMode[CTRL_SAMPLING_MODES];
/* Unknown. */
u8 cableTypeReq;
/* Unknown. */
u8 unk15;
union {
struct {
/* The busy status of the SYSCON microcontroller for the first communication
* function (_sceCtrlSysconCmdIntr1).
*/
u8 intr1;
/* The busy status of the SYSCON microcontroller for the second communication
* function (_sceCtrlSysconCmdIntr2).
*/
u8 intr2;
/** Reserved. */
u8 resv[2];
} busy;
u32 status;
} sysconStatus;
/* SCE_TRUE = reset the PSP's idle timer, SCE_FALSE = don't reset it. */
u8 cancelIdleTimer;
/* Poll mode of the controller. One of ::SceCtrlPadPollMode. */
u8 pollMode;
/* The number of samples of the PSP hardware button registers before
* suspending the PSP device.
*/
s16 suspendSamples;
/* The number of SYSCON hardware button transfers left. */
s32 sysconTransfersLeft;
/* The packets sent to SYSCON in order to obtain fresh button data. */
SceSysconPacket sysPacket[2];
/* The internal controller data for User mode applications. */
SceCtrlInternalData userModeData;
/* The internal controller data for Kernel mode applications. */
SceCtrlInternalData kernelModeData;
/* The rapid fire structure objects. */
SceCtrlRapidFire rapidFire[CTRL_BUTTONS_RAPID_FIRE_SLOTS];
/* The obtained button data from a SYSCON hardware transfer. */
u32 rawButtons;
/* Previously pressed kernel buttons. */
u32 prevKernelButtons[2];
/* Previously pressed buttons (one frame past the current one). Button
* emulation data is applied to it.
*/
u32 prevButtons;
/* Currently pressed User buttons, combined with custom settings,
* like rapid fire events and masked buttons.
*/
u32 userButtons;
/* Records the possibly user-modified, pressed buttons of the past
* VBlank interrupt before the current one.
*/
u32 prevModifiedButtons;
/* The current X axis value of the analog pad obtained by a SYSCON
* transfer.
*/
u8 analogX;
/* The current Y axis value of the analog pad obtained by a SYSCON
* transfer.
*/
u8 analogY;
/* Unknown. */
s8 unk582;
/* Unknown. */
s8 unk583;
/* The emulation data structure objects. */
SceCtrlEmulationData emulationData[CTRL_DATA_EMULATION_SLOTS];
/* The buttons which can be read in User mode applications. */
u32 userModeButtons;
/* Bit mask containing the buttons which status (pressed, un-pressed)
* is normally recognized.
*/
u32 maskSupportButtons;
/* Bit mask containing the buttons which are simulated as being
* pressed, although the user might not press them.
*/
u32 maskApplyButtons;
/* General group of buttons which are able to reset the PSP's idle
* timer.
*/
s32 idleResetAllSupportedButtons;
/* Group of buttons which reset the PSP's idle timer the first frame of a
* time period where they are being pressed. They reset the timer when HOLD
* mode is inactive.
*/
s32 oneTimeIdleResetButtons;
/* Group of buttons which reset the PSP's idle timer during every frame where
* they are being pressed. They reset the timer when HOLD mode is inactive.
*/
s32 allTimeIdleResetButtons;
/* Group of buttons which reset the PSP's idle timer the first frame of a
* time period where they are being pressed. They reset the timer when HOLD
* mode is active.
*/
s32 oneTimeIdleHoldModeResetButtons;
/* Group of buttons which reset the PSP's idle timer during every frame where
* they are being pressed. They reset the timer when HOLD mode is active.
*/
s32 allTimeIdleHoldModeResetButtons;
/* Analog Stick threshold used to cancel the PSP's idle timer when
* HOLD mode is inactive.
*/
s32 unHoldThreshold;
/* Analog Stick threshold used to cancel the PSP's idle timer when
* HOLD mode is active.
*/
s32 holdThreshold;
/* The button callback objects for the controller module. */
SceCtrlButtonCallback buttonCallback[CTRL_BUTTON_CALLBACK_SLOTS];
/* Unknown. */
s32 unk768;
/* Pointers to transferHandlers to copy external input data into the PSP internal controller buffers. */
SceCtrlInputDataTransferHandler *transferHandler[CTRL_NUM_EXTERNAL_INPUT_MODES];
/* Pointers to external input data buffers to copy via the <transferHandler>. */
void *extInputDataSource[CTRL_NUM_EXTERNAL_INPUT_MODES];
} SceCtrl;
static s32 _sceCtrlSysEventHandler(s32 eventId, char *eventName, void *param, s32 *result);
static SceUInt _sceCtrlDummyAlarm(void *common);
static s32 _sceCtrlVblankIntr(s32 subIntNm, void *arg);
static s32 _sceCtrlTimerIntr(s32 timerId, s32 count, void *common, s32 arg4);
static s32 _sceCtrlSysconCmdIntr1(SceSysconPacket *sysPacket, void *argp);
static s32 _sceCtrlSysconCmdIntr2(SceSysconPacket *packet, void *argp);
static s32 _sceCtrlUpdateButtons(u32 rawButtons, u8 aX, u8 aY);
static s32 _sceCtrlReadBuf(SceCtrlDataExt *data, u8 nBufs, u32 arg3, u8 mode);
/*
* The controller module's manager. Keeps track of every important
* controller data.
*/
SceCtrl g_ctrl;
SceKernelDeci2Ops g_ctrlDeci2Ops = {
.size = 0x28,
.ops = {
[0] = (void *)sceCtrlGetSamplingMode,
[1] = (void *)sceCtrlGetSamplingCycle,
[2] = (void *)sceCtrlPeekBufferPositive,
[3] = (void *)sceCtrlPeekLatch,
[4] = (void *)sceCtrlSetRapidFire,
[5] = (void *)sceCtrlClearRapidFire,
[6] = (void *)sceCtrlSetButtonEmulation,
[7] = (void *)sceCtrlSetAnalogEmulation,
[8] = (void *)sceCtrlExtendInternalCtrlBuffers
},
};
/*
* The controller module's SYSCON event handler. It is used to handle
* PSP hardware (power) effects, i.e. entering Sleep mode and resuming
* from Sleep mode.
*/
SceSysEventHandler g_ctrlSysEvent = {
.size = sizeof(SceSysEventHandler),
.name = "SceCtrl",
.typeMask = SCE_SUSPEND_EVENTS | SCE_RESUME_EVENTS,
.handler = _sceCtrlSysEventHandler,
.gp = 0,
.busy = SCE_FALSE,
.next = NULL,
.reserved = {
[0] = 0,
[1] = 0,
[2] = 0,
[3] = 0,
[4] = 0,
[5] = 0,
[6] = 0,
[7] = 0,
[8] = 0,
}
};
/*
* The 64 interval controller button data buffers used for User mode
* applications. The member "buttons" of these buffers only contains
* User buttons.
*/
SceCtrlData ctrlUserBufs[CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS];
/*
* The 64 interval controller button data buffers used for Kernel mode
* applications.
*/
SceCtrlData ctrlKernelBufs[CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS];
s32 sceCtrlInit(void)
{
s32 eventId;
s32 appType;
s32 timerId;
u32 supportedUserButtons;
void (*func)(SceKernelDeci2Ops *);
SceKernelDeci2Ops *deci2Ops;
s32 pspModel;
memset(&g_ctrl, 0, sizeof(SceCtrl));
g_ctrl.pollMode = SCE_CTRL_POLL_ACTIVE;
g_ctrl.userModeData.pCtrlInputBuffers[0] = ctrlUserBufs;
g_ctrl.analogY = CTRL_ANALOG_PAD_CENTER_VALUE;
g_ctrl.analogX = CTRL_ANALOG_PAD_CENTER_VALUE;
g_ctrl.kernelModeData.pCtrlInputBuffers[0] = ctrlKernelBufs;
g_ctrl.sysconTransfersLeft = -1;
/*
* Create the event used to signal the end of an update process of
* internal controller button data buffers.
*/
eventId = sceKernelCreateEventFlag("SceCtrl", SCE_KERNEL_EW_OR, 0, NULL);
g_ctrl.updateEventId = eventId;
/*
* Allocate a timer used for the custom update interval set by the
* user.
*/
timerId = sceSTimerAlloc();
if (timerId < SCE_ERROR_OK)
return timerId;
g_ctrl.timerID = timerId;
sceSTimerSetPrscl(timerId, 1, 48);
g_ctrl.unk15 = -1;
sceKernelRegisterSysEventHandler(&g_ctrlSysEvent);
sceSysconSetAffirmativeRertyMode(0);
appType = sceKernelApplicationType();
if (appType == SCE_INIT_APPLICATION_UPDATER)
supportedUserButtons = CTRL_USER_MODE_BUTTONS_EXTENDED;
if (appType > SCE_INIT_APPLICATION_UPDATER) {
supportedUserButtons = CTRL_USER_MODE_BUTTONS_DEFAULT;
if (appType == SCE_INIT_APPLICATION_POPS)
supportedUserButtons = CTRL_USER_MODE_BUTTONS_EXTENDED;
}
if (appType == 0) {
supportedUserButtons = CTRL_USER_MODE_BUTTONS_DEFAULT;
}
else {
supportedUserButtons = CTRL_USER_MODE_BUTTONS_DEFAULT;
if (appType == SCE_INIT_APPLICATION_VSH)
supportedUserButtons = CTRL_USER_MODE_BUTTONS_EXTENDED;
}
g_ctrl.userModeButtons = supportedUserButtons;
g_ctrl.maskApplyButtons = 0;
g_ctrl.maskSupportButtons = supportedUserButtons;
pspModel = sceKernelGetModel();
switch (pspModel) {
case PSP_GO: case 5: case 7: case 9:
g_ctrl.idleResetAllSupportedButtons = CTRL_ALL_SUPPORTED_BUTTONS;
break;
default:
g_ctrl.idleResetAllSupportedButtons = 0x1FFF3F9;
break;
}
g_ctrl.oneTimeIdleResetButtons = CTRL_ALL_SUPPORTED_BUTTONS;
g_ctrl.allTimeIdleResetButtons = CTRL_ALL_TIME_IDLE_TIMER_RESET_BUTTONS;
g_ctrl.oneTimeIdleHoldModeResetButtons = 0x390E0000;
g_ctrl.allTimeIdleHoldModeResetButtons = 0;
g_ctrl.unHoldThreshold = CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER;
g_ctrl.holdThreshold = CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER;
sceKernelRegisterSubIntrHandler(SCE_VBLANK_INT, 0x13, _sceCtrlVblankIntr, NULL);
sceKernelEnableSubIntr(SCE_VBLANK_INT, 0x13);
deci2Ops = sceKernelDeci2pReferOperations();
if (deci2Ops != NULL && deci2Ops->size == 48) {
func = (void (*)(SceKernelDeci2Ops *))deci2Ops->ops[10];
func(&g_ctrlDeci2Ops);
}
return SCE_ERROR_OK;
}
s32 sceCtrlEnd(void)
{
s32 timerId;
s32 sysconStatus;
sceKernelUnregisterSysEventHandler(&g_ctrlSysEvent);
sceSysconSetAffirmativeRertyMode(1);
sceDisplayWaitVblankStart();
timerId = g_ctrl.timerID;
g_ctrl.timerID = -1;
if (timerId >= 0) {
sceSTimerStopCount(timerId);
sceSTimerFree(timerId);
}
sceKernelReleaseSubIntrHandler(SCE_VBLANK_INT, 0x13);
sceKernelDeleteEventFlag(g_ctrl.updateEventId);
sysconStatus = g_ctrl.sysconStatus.status;
while (sysconStatus != 0) {
sceDisplayWaitVblankStart();
sysconStatus = g_ctrl.sysconStatus.status;
}
return SCE_ERROR_OK;
}
s32 sceCtrlSuspend(void)
{
s32 cycle;
cycle = g_ctrl.updateCycle;
if (cycle != 0)
sceSTimerStopCount(g_ctrl.timerID);
else
sceKernelDisableSubIntr(SCE_VBLANK_INT, 0x13);
return SCE_ERROR_OK;
}
s32 sceCtrlResume(void)
{
s32 status;
status = sceSyscon_driver_97765E27();
if (status == 1)
g_ctrl.prevButtons |= 0x20000000;
else
g_ctrl.prevButtons &= ~0x20000000;
g_ctrl.unk15 = -1;
if (g_ctrl.updateCycle == 0) {
sceKernelEnableSubIntr(SCE_VBLANK_INT, 0x13);
}
else {
sceSTimerStartCount(g_ctrl.timerID);
sceSTimerSetHandler(g_ctrl.timerID, g_ctrl.updateCycle, _sceCtrlTimerIntr, NULL);
}
return SCE_ERROR_OK;
}
u32 sceCtrlSetPollingMode(u8 pollMode)
{
g_ctrl.pollMode = pollMode;
return SCE_ERROR_OK;
}
u32 sceCtrlGetSamplingMode(u8 *mode)
{
s32 oldK1;
oldK1 = pspShiftK1();
if (pspK1PtrOk(mode))
*mode = g_ctrl.samplingMode[!pspK1IsUserMode()];
pspSetK1(oldK1);
return SCE_ERROR_OK;
}
s32 sceCtrlSetSamplingMode(u8 mode)
{
s32 intrState;
s32 index;
u8 prevMode;
s32 oldK1;
if (mode > CTRL_SAMPLING_MODE_MAX_MODE)
return SCE_ERROR_INVALID_MODE;
intrState = sceKernelCpuSuspendIntr();
oldK1 = pspShiftK1();
index = !pspK1IsUserMode();
prevMode = g_ctrl.samplingMode[index];
g_ctrl.samplingMode[index] = mode;
pspSetK1(oldK1);
sceKernelCpuResumeIntr(intrState);
return prevMode;
}
u32 sceCtrlGetSamplingCycle(u32 *cycle)
{
s32 oldK1;
oldK1 = pspShiftK1();
if (pspK1PtrOk(cycle))
*cycle = g_ctrl.updateCycle;
pspSetK1(oldK1);
return SCE_ERROR_OK;
}
s32 sceCtrlSetSamplingCycle(u32 cycle)
{
s32 intrState;
u32 prevCycle;
s32 sdkVersion;
s32 oldK1;
oldK1 = pspShiftK1();
intrState = sceKernelCpuSuspendIntr();
if (cycle == 0) {
prevCycle = g_ctrl.updateCycle;
sceKernelEnableSubIntr(SCE_VBLANK_INT, 0x13);
g_ctrl.updateCycle = 0;
sceSTimerSetHandler(g_ctrl.timerID, 0, NULL, NULL);
sceSTimerStopCount(g_ctrl.timerID);
}
else if (cycle < CTRL_BUFFER_UPDATE_MIN_CUSTOM_CYCLES || cycle > CTRL_BUFFER_UPDATE_MAX_CUSTOM_CYCLES) {
return SCE_ERROR_INVALID_VALUE;
}
else {
prevCycle = g_ctrl.updateCycle;
sceSTimerStartCount(g_ctrl.timerID);
g_ctrl.updateCycle = cycle;
sdkVersion = sceKernelGetCompiledSdkVersion();
cycle = (sdkVersion > CTRL_BUF_UPDATE_INCREASE_CYCLE_SDK_VER) ? cycle : cycle + 1;
sceSTimerSetHandler(g_ctrl.timerID, cycle, _sceCtrlTimerIntr, NULL);
sceKernelDisableSubIntr(SCE_VBLANK_INT, 0x13);
}
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return prevCycle;
}
u32 sceCtrlGetIdleCancelKey(u32 *oneTimeResetButtons, u32 *allTimeResetButtons, u32 *oneTimeHoldResetButtons,
u32 *allTimeHoldResetButtons)
{
if (oneTimeResetButtons != NULL)
*oneTimeResetButtons = g_ctrl.oneTimeIdleResetButtons;
if (allTimeResetButtons != NULL)
*allTimeResetButtons = g_ctrl.allTimeIdleResetButtons;
if (oneTimeHoldResetButtons != NULL)
*oneTimeHoldResetButtons = g_ctrl.oneTimeIdleHoldModeResetButtons;
if (allTimeHoldResetButtons != NULL)
*allTimeHoldResetButtons = g_ctrl.allTimeIdleHoldModeResetButtons;
return SCE_ERROR_OK;
}
u32 sceCtrlSetIdleCancelKey(u32 oneTimeResetButtons, u32 allTimeResetButtons, u32 oneTimeHoldResetButtons,
u32 allTimeHoldResetButtons)
{
g_ctrl.oneTimeIdleResetButtons = oneTimeResetButtons;
g_ctrl.allTimeIdleResetButtons = allTimeResetButtons;
g_ctrl.oneTimeIdleHoldModeResetButtons = oneTimeHoldResetButtons;
g_ctrl.allTimeIdleHoldModeResetButtons = allTimeHoldResetButtons;
return SCE_ERROR_OK;
}
s32 sceCtrlGetIdleCancelThreshold(s32 *iUnHoldThreshold, s32 *iHoldThreshold)
{
s32 oldK1;
s32 intrState;
oldK1 = pspShiftK1();
if (!pspK1PtrOk(iUnHoldThreshold) || !pspK1PtrOk(iHoldThreshold)) {
pspSetK1(oldK1);
return SCE_ERROR_PRIV_REQUIRED;
}
intrState = sceKernelCpuSuspendIntr();
if (iUnHoldThreshold != NULL)
*iUnHoldThreshold = (g_ctrl.unHoldThreshold == CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER) ? -1 : g_ctrl.unHoldThreshold;
if (iHoldThreshold != NULL)
*iHoldThreshold = (g_ctrl.holdThreshold == CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER) ? -1 : g_ctrl.holdThreshold;
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return SCE_ERROR_OK;
}
s32 sceCtrlSetIdleCancelThreshold(s32 iUnHoldThreshold, s32 iHoldThreshold)
{
s32 intrState;
if (((iUnHoldThreshold < -1 || iUnHoldThreshold > 128) && iHoldThreshold < -1) || iHoldThreshold > 128)
return SCE_ERROR_INVALID_VALUE;
intrState = sceKernelCpuSuspendIntr();
g_ctrl.holdThreshold = (iHoldThreshold == -1) ? CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER : iHoldThreshold;
g_ctrl.unHoldThreshold = (iUnHoldThreshold == -1) ? CTRL_ANALOG_PAD_NO_CANCEL_IDLE_TIMER : iUnHoldThreshold;
sceKernelCpuResumeIntr(intrState);
return SCE_ERROR_OK;
}
s16 sceCtrlGetSuspendingExtraSamples(void)
{
return g_ctrl.suspendSamples;
}
s32 sceCtrlSetSuspendingExtraSamples(s16 suspendSamples)
{
if (suspendSamples > CTRL_MAX_EXTRA_SUSPEND_SAMPLES)
return SCE_ERROR_INVALID_VALUE;
g_ctrl.suspendSamples = (suspendSamples == 1) ? 0 : suspendSamples;
return SCE_ERROR_OK;
}
s32 sceCtrlExtendInternalCtrlBuffers(u8 inputMode, SceCtrlInputDataTransferHandler *transferHandler, void *inputSource)
{
SceUID poolId;
SceCtrlDataExt *ctrlBuf;
if (inputMode != SCE_CTRL_EXTERNAL_INPUT_DUALSHOCK_3 || inputMode != SCE_CTRL_EXTERNAL_INPUT_UNKNOWN_2)
return SCE_ERROR_INVALID_VALUE;
if (g_ctrl.transferHandler[inputMode - 1] == NULL) {
poolId = sceKernelCreateFpl("SceCtrlBuf", SCE_KERNEL_PRIMARY_KERNEL_PARTITION, 0,
2 * sizeof(SceCtrlDataExt) * CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS, 1, NULL);
if (poolId < 0)
return poolId;
sceKernelTryAllocateFpl(poolId, (void **)&ctrlBuf);
g_ctrl.kernelModeData.pCtrlInputBuffers[inputMode] = ctrlBuf + CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
g_ctrl.userModeData.pCtrlInputBuffers[inputMode] = ctrlBuf;
}
g_ctrl.extInputDataSource[inputMode - 1] = inputSource;
g_ctrl.transferHandler[inputMode - 1] = transferHandler;
return SCE_ERROR_OK;
}
s32 sceCtrlPeekLatch(SceCtrlLatch *latch)
{
SceCtrlInternalData *latchPtr;
s32 intrState;
s32 oldK1;
oldK1 = pspShiftK1();
intrState = sceKernelCpuSuspendIntr();
if (!pspK1PtrOk(latch)) {
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return SCE_ERROR_PRIV_REQUIRED;
}
if (pspK1IsUserMode())
latchPtr = &g_ctrl.userModeData;
else
latchPtr = &g_ctrl.kernelModeData;
latch->buttonMake = latchPtr->btnMake;
latch->buttonBreak = latchPtr->btnBreak;
latch->buttonPress = latchPtr->btnPress;
latch->buttonRelease = latchPtr->btnRelease;
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return latchPtr->readLatchCount;
}
s32 sceCtrlReadLatch(SceCtrlLatch *latch)
{
SceCtrlInternalData *latchPtr;
s32 intrState;
s32 readLatchCount;
s32 oldK1;
oldK1 = pspShiftK1();
intrState = sceKernelCpuSuspendIntr();
if (!pspK1PtrOk(latch)) {
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return SCE_ERROR_PRIV_REQUIRED;
}
if (pspK1IsUserMode())
latchPtr = &g_ctrl.userModeData;
else
latchPtr = &g_ctrl.kernelModeData;
readLatchCount = latchPtr->readLatchCount;
latchPtr->readLatchCount = 0;
latch->buttonMake = latchPtr->btnMake;
latch->buttonBreak = latchPtr->btnBreak;
latch->buttonPress = latchPtr->btnPress;
latch->buttonRelease = latchPtr->btnRelease;
latchPtr->btnMake = 0;
latchPtr->btnBreak = 0;
latchPtr->btnPress = 0;
latchPtr->btnRelease = 0;
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return readLatchCount;
}
s32 sceCtrlPeekBufferPositive(SceCtrlData *data, u8 nBufs)
{
return _sceCtrlReadBuf((SceCtrlDataExt *)data, nBufs, SCE_CTRL_EXTERNAL_INPUT_NONE, PEEK_BUFFER_POSITIVE);
}
s32 sceCtrlPeekBufferNegative(SceCtrlData *data, u8 nBufs)
{
return _sceCtrlReadBuf((SceCtrlDataExt *)data, nBufs, SCE_CTRL_EXTERNAL_INPUT_NONE, PEEK_BUFFER_NEGATIVE);
}
s32 sceCtrlReadBufferPositive(SceCtrlData *data, u8 nBufs)
{
return _sceCtrlReadBuf((SceCtrlDataExt *)data, nBufs, SCE_CTRL_EXTERNAL_INPUT_NONE, READ_BUFFER_POSITIVE);
}
s32 sceCtrlReadBufferNegative(SceCtrlData *data, u8 nBufs)
{
return _sceCtrlReadBuf((SceCtrlDataExt *)data, nBufs, SCE_CTRL_EXTERNAL_INPUT_NONE, READ_BUFFER_NEGATIVE);
}
s32 sceCtrlPeekBufferPositiveExtra(u32 inputMode, SceCtrlDataExt *data, u8 nBufs)
{
return _sceCtrlReadBuf(data, nBufs, inputMode, PEEK_BUFFER_POSITIVE_EXTRA);
}
s32 sceCtrlPeekBufferNegativeExtra(u32 inputMode, SceCtrlDataExt *data, u8 nBufs)
{
return _sceCtrlReadBuf(data, nBufs, inputMode, PEEK_BUFFER_NEGATIVE_EXTRA);
}
s32 sceCtrlReadBufferPositiveExtra(u32 inputMode, SceCtrlDataExt *data, u8 nBufs)
{
return _sceCtrlReadBuf(data, nBufs, inputMode, READ_BUFFER_POSITIVE_EXTRA);
}
s32 sceCtrlReadBufferNegativeExtra(u32 inputMode, SceCtrlDataExt *data, u8 nBufs)
{
return _sceCtrlReadBuf(data, nBufs, inputMode, READ_BUFFER_NEGATIVE_EXTRA);
}
s32 sceCtrlClearRapidFire(u8 slot)
{
if (slot > CTRL_BUTTONS_RAPID_FIRE_MAX_SLOT)
return SCE_ERROR_INVALID_INDEX;
g_ctrl.rapidFire[slot].uiMask = 0;
return SCE_ERROR_OK;
}
s32 sceCtrlSetRapidFire(u8 slot, u32 uiMask, u32 uiTrigger, u32 uiTarget, u8 uiDelay,
u8 uiMake, u8 uiBreak)
{
u32 usedButtons;
u32 invalidButtons;
s32 oldK1;
s32 intrState;
if (slot > CTRL_BUTTONS_RAPID_FIRE_MAX_SLOT)
return SCE_ERROR_INVALID_INDEX;
if ((uiDelay | uiMake | uiBreak) > CTRL_MAX_INTERNAL_CONTROLLER_BUFFER)
return SCE_ERROR_INVALID_VALUE;
oldK1 = pspShiftK1();
usedButtons = uiMask | uiTrigger | uiTarget;
/*
* Don't allow kernel buttons or the HOLD button to be used in User
* mode applications.
*/
if (pspK1IsUserMode()) {
invalidButtons = (~g_ctrl.userModeButtons | SCE_CTRL_HOLD);
if (invalidButtons & usedButtons) {
pspSetK1(oldK1);
return SCE_ERROR_PRIV_REQUIRED;
}
}
intrState = sceKernelCpuSuspendIntr();
g_ctrl.rapidFire[slot].uiMake = uiMake;
g_ctrl.rapidFire[slot].uiMask = uiMask;
g_ctrl.rapidFire[slot].uiTrigger = uiTrigger;
g_ctrl.rapidFire[slot].uiTarget = uiTarget;
g_ctrl.rapidFire[slot].uiBreak = uiBreak;
g_ctrl.rapidFire[slot].uiDelay = uiDelay;
g_ctrl.rapidFire[slot].eventData = 0;
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return SCE_ERROR_OK;
}
s32 sceCtrlSetAnalogEmulation(u8 slot, u8 aX, u8 aY, u32 uiMake)
{
if (slot > CTRL_DATA_EMULATION_MAX_SLOT)
return SCE_ERROR_INVALID_VALUE;
g_ctrl.emulationData[slot].analogX = aX;
g_ctrl.emulationData[slot].analogY = aY;
g_ctrl.emulationData[slot].uiAnalogMake = uiMake;
return SCE_ERROR_OK;
}
s32 sceCtrlSetButtonEmulation(u8 slot, u32 userButtons, u32 kernelButtons, u32 uiMake)
{
if (slot > CTRL_DATA_EMULATION_MAX_SLOT)
return SCE_ERROR_INVALID_VALUE;
g_ctrl.emulationData[slot].userButtons = userButtons;
g_ctrl.emulationData[slot].kernelButtons = kernelButtons;
g_ctrl.emulationData[slot].uiButtonMake = uiMake;
return SCE_ERROR_OK;
}
u32 sceCtrlGetButtonIntercept(u32 buttons)
{
s32 intrState;
s32 btnMaskMode;
intrState = sceKernelCpuSuspendIntr();
btnMaskMode = SCE_CTRL_MASK_IGNORE_BUTTONS;
if (g_ctrl.maskSupportButtons & buttons)
btnMaskMode = (g_ctrl.maskApplyButtons & buttons) ? SCE_CTRL_MASK_APPLY_BUTTONS : SCE_CTRL_MASK_NO_MASK;
sceKernelCpuResumeIntr(intrState);
return btnMaskMode;
}
u32 sceCtrlSetButtonIntercept(u32 buttons, u32 buttonMaskMode)
{
s32 intrState;
s32 prevBtnMaskMode;
intrState = sceKernelCpuSuspendIntr();
/* Return the previous mask type of the specified buttons. */
prevBtnMaskMode = SCE_CTRL_MASK_IGNORE_BUTTONS;
if (buttons & g_ctrl.maskSupportButtons)
prevBtnMaskMode = (buttons & g_ctrl.maskApplyButtons) ? SCE_CTRL_MASK_APPLY_BUTTONS : SCE_CTRL_MASK_NO_MASK;
if (buttonMaskMode != SCE_CTRL_MASK_NO_MASK) {
/* Simulate the specified buttons as always not being pressed. */
if (buttonMaskMode == SCE_CTRL_MASK_IGNORE_BUTTONS) {
g_ctrl.maskSupportButtons &= ~buttons;
g_ctrl.maskApplyButtons &= ~buttons;
}
/* Simulate the specified buttons as always being pressed. */
else if (buttonMaskMode == SCE_CTRL_MASK_APPLY_BUTTONS) {
g_ctrl.maskSupportButtons |= buttons;
g_ctrl.maskApplyButtons |= buttons;
}
}
/* Remove any existing simulation from the specified buttons. */
else {
g_ctrl.maskSupportButtons |= buttons;
g_ctrl.maskApplyButtons &= ~buttons;
}
sceKernelCpuResumeIntr(intrState);
return prevBtnMaskMode;
}
s32 sceCtrlSetSpecialButtonCallback(u32 slot, u32 buttonMask, SceKernelButtonCallbackFunction callback, void *opt)
{
s32 intrState;
if (slot > CTRL_BUTTON_CALLBACK_MAX_SLOT)
return SCE_ERROR_INVALID_INDEX;
intrState = sceKernelCpuSuspendIntr();
g_ctrl.buttonCallback[slot].buttonMask = buttonMask;
g_ctrl.buttonCallback[slot].callback = callback;
g_ctrl.buttonCallback[slot].arg = opt;
g_ctrl.buttonCallback[slot].gp = pspGetGp();
sceKernelCpuResumeIntr(intrState);
return SCE_ERROR_OK;
}
u32 sceCtrl_driver_6C86AF22(s32 arg1)
{
g_ctrl.unk768 = arg1;
return SCE_ERROR_OK;
}
u32 sceCtrl_driver_5886194C(s8 arg1)
{
g_ctrl.unk583 = arg1;
return SCE_ERROR_OK;
}
u32 sceCtrlUpdateCableTypeReq(void)
{
g_ctrl.cableTypeReq = 1;
return SCE_ERROR_OK;
}
/*
* Handle PSP hardware events like entering low-power state or
* resuming from low-power state.
*
* Entering low-power state:
* Put the controller device into a low-power state.
* Suspend the update timer, if it is used, or disable the VBlank
* interrupt to stop the updates of the internal controller data
* buffers.
*
* Resuming from low-power state:
* Bring the controller device back from a low-power state.
* Re-start the update timer, if it was used before, or re-enable the
* VBlank interrupt to re-start the updates of the internal controller
* data buffers.
*
* Returns 0 on success.
*/
static s32 _sceCtrlSysEventHandler(s32 eventId, char *eventName, void *param, s32 *result)
{
s32 sysconStatus;
(void)eventName;
(void)param;
(void)result;
if (eventId == 0x402) {
sysconStatus = g_ctrl.sysconStatus.status;
if (sysconStatus == 0)
return SCE_ERROR_OK;
if (g_ctrl.sysconTransfersLeft == 0)
return SCE_ERROR_OK;
return SCE_ERROR_BUSY;
}
if (eventId < 0x403) {
if (eventId == 0x400)
g_ctrl.sysconTransfersLeft = g_ctrl.suspendSamples;
return SCE_ERROR_OK;
}
else if (eventId == 0x400C) {
return sceCtrlSuspend();
}
else {
if (eventId == 0x1000C) {
sceCtrlResume();
g_ctrl.sysconTransfersLeft = -1;
}
return SCE_ERROR_OK;
}
}
/*
* The alarm handler updates the internal controller buffers with
* already transfered controller device input data. It does not
* communicate via the SYSCON microcontroller with the hardware registers
* in order to obtain fresh button data.
*
* It is called when one (or both) of the following conditions
* are true:
* 1) The SYSCON microcontroller is busy.
* 2) The controller driver is NOT polling for new controller device
* input.
*
* Returns 0.
*/
static SceUInt _sceCtrlDummyAlarm(void *opt)
{
s32 intrState;
u32 rawButtons;
(void)opt;
intrState = sceKernelCpuSuspendIntr();
rawButtons = g_ctrl.rawButtons;
if (g_ctrl.sysconTransfersLeft == 0)
rawButtons &= ~0x1FFFF;
_sceCtrlUpdateButtons(rawButtons, g_ctrl.analogX, g_ctrl.analogY);
/* Set the event flag to indicate a finished update interval. */
sceKernelSetEventFlag(g_ctrl.updateEventId, UPDATE_INTERRUPT_EVENT_FLAG_ON);
sceKernelCpuResumeIntr(intrState);
return SCE_ERROR_OK;
}
/*
* The VBlank interrupt handler is called whenever the VBlank interrupt
* occurs (approximately 60 times/second). Its purpose is to communicate
* with the hardware button registers via the SYSCON microcontroller to
* update the internal controller data buffers with the new controller
* device input data.
*
* A SYSCON hardware register data transfer is requested when the following
* two conditions are true:
* 1) the SYSCON microcontroller is NOT busy.
* 2) The controller driver is polling for new controller device input.
*
* Returns -1.
*/
static s32 _sceCtrlVblankIntr(s32 subIntNm, void *arg)
{
s32 intrState;
s32 status;
(void)subIntNm;
(void)arg;
intrState = sceKernelCpuSuspendIntr();
/*
* Ensure that calling the VBlank interrupt handler is the right
* choice (and not the custom user timer handler).
*/
if (g_ctrl.updateCycle == 0) {
if (g_ctrl.sysconStatus.busy.intr1 == SCE_FALSE && g_ctrl.pollMode == SCE_CTRL_POLL_ACTIVE) {
g_ctrl.sysconStatus.busy.intr1 = SCE_TRUE;
/* Specify the requested controller device input data. */
if ((g_ctrl.samplingMode[USER_MODE] | g_ctrl.samplingMode[KERNEL_MODE]) == SCE_CTRL_INPUT_DIGITAL_ONLY)
g_ctrl.sysPacket[0].tx[PSP_SYSCON_TX_CMD] = PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY;
else
g_ctrl.sysPacket[0].tx[PSP_SYSCON_TX_CMD] = PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY_ANALOG;
g_ctrl.sysPacket[0].tx[PSP_SYSCON_TX_LEN] = 2;
status = sceSysconCmdExecAsync(&g_ctrl.sysPacket[0], 1, _sceCtrlSysconCmdIntr1, NULL);
if (status < SCE_ERROR_OK)
g_ctrl.sysconStatus.busy.intr1 = SCE_FALSE;
}
else {
sceKernelSetAlarm(CTRL_ALARM_START_TIME, _sceCtrlDummyAlarm, NULL);
}
}
if (g_ctrl.cancelIdleTimer != SCE_FALSE) {
g_ctrl.cancelIdleTimer = SCE_FALSE;
sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT);
}
sceKernelCpuResumeIntr(intrState);
return -1;
}
/*
* The timer handler is called every 'g_ctrl.cycle' microseconds
* (cycle greater 0). Its purpose is to communicate with the hardware
* button registers via the SYSCON microcontroller to update the
* internal controller data buffers with the new controller device input
* data.
*
* A SYSCON hardware register data transfer is requested when the following
* two conditions are true:
* 1) the SYSCON microcontroller is NOT busy.
* 2) The controller driver is polling for new controller device input.
*
* Returns -1.
*/
static s32 _sceCtrlTimerIntr(s32 timerId, s32 count, void *common, s32 arg4)
{
u8 sysconCtrlCmd;
s32 intrState;
s32 status;
(void)timerId;
(void)count;
(void)common;
(void)arg4;
sysconCtrlCmd = PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY;
intrState = sceKernelCpuSuspendIntr();
/*
* Ensure that calling the timer handler is the right choice
* (and not the VBlank interrupt handler).
*/
if (g_ctrl.updateCycle != 0) {
if ((g_ctrl.sysconStatus.busy.intr1 == SCE_FALSE) && (g_ctrl.pollMode == SCE_CTRL_POLL_ACTIVE)) {
g_ctrl.sysconStatus.busy.intr1 = SCE_TRUE;
/* Specify the requested controller device input data. */
if (g_ctrl.samplingMode[USER_MODE] != SCE_CTRL_INPUT_DIGITAL_ONLY)
sysconCtrlCmd = PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY_ANALOG;
g_ctrl.sysPacket[0].tx[PSP_SYSCON_TX_CMD] = sysconCtrlCmd;
status = sceSysconCmdExecAsync(&g_ctrl.sysPacket[0], 1, _sceCtrlSysconCmdIntr1, NULL);
if (status < SCE_ERROR_OK)
g_ctrl.sysconStatus.busy.intr1 = SCE_FALSE;
}
else {
sceKernelSetAlarm(CTRL_ALARM_START_TIME, _sceCtrlDummyAlarm, NULL);
}
}
if (g_ctrl.cancelIdleTimer != SCE_FALSE) {
g_ctrl.cancelIdleTimer = SCE_FALSE;
sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT);
}
sceKernelCpuResumeIntr(intrState);
return -1;
}
/*
* Receive a SYSCON packet with the transferred button data from the
* hardware registers. Update the internal controller data buffers of
* the controller module with the obtained button data.
*
* Returns 0.
*/
static s32 _sceCtrlSysconCmdIntr1(SceSysconPacket *sysPacket, void *argp)
{
u32 rawButtons;
s32 intrState;
s32 status;
u32 curButtons, prevButtons, newButtons;
u8 analogX, analogY;
u8 aXCenterOffset, aYCenterOffset;
u8 idleVal;
u8 sampling;
u32 oneTimeIdleResetButtons, allTimeIdleResetButtons;
u32 idleResetButtons;
(void)argp;
curButtons = 0;
g_ctrl.sysconStatus.busy.intr1 = SCE_FALSE;
if (g_ctrl.sysconTransfersLeft > 0)
g_ctrl.sysconTransfersLeft--;
if (g_ctrl.sysconTransfersLeft == 0) {
intrState = sceKernelCpuSuspendIntr();
if (g_ctrl.sysconTransfersLeft == 0)
rawButtons = g_ctrl.rawButtons & ~0x1FFFF;
else
rawButtons = g_ctrl.rawButtons;
_sceCtrlUpdateButtons(rawButtons, g_ctrl.analogX, g_ctrl.analogY);
/* Set the event flag to indicate a finished update interval. */
sceKernelSetEventFlag(g_ctrl.updateEventId, UPDATE_INTERRUPT_EVENT_FLAG_ON);
sceKernelCpuResumeIntr(intrState);
return SCE_ERROR_OK;
}
else {
prevButtons = g_ctrl.rawButtons;
/*
* A received SYSCON data package differs in size and content. Size and
* content for the controller module depend on the command send to the
* SYSCON microcontroller. We test against the different commands in
* order to obtain the button data from the right package location.
*
* package example_1: The command
* PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY_ANALOG requests the largest
* package and contains both kernel and user buttons as well as analog
* stick data.
* package example_2: The command PSP_SYSCON_CMD_GET_ANALOG requests the
* smallest package, containing only analog stick data.
*/
if (sysPacket->tx[PSP_SYSCON_TX_CMD] != PSP_SYSCON_CMD_GET_DIGITAL_KEY
&& sysPacket->tx[PSP_SYSCON_TX_CMD] != PSP_SYSCON_CMD_GET_DIGITAL_KEY_ANALOG) {
if (sysPacket->tx[PSP_SYSCON_TX_CMD] >= PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY
&& sysPacket->tx[PSP_SYSCON_TX_CMD] <= PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY_ANALOG) {
curButtons = (((sysPacket->rx[PSP_SYSCON_RX_DATA(3)] & 3) << 28)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(2)] & 0xBF) << 20)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 0xF0) << 12)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(0)] & 0xF0) << 8)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 6) << 7)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(0)] & 0xF) << 4)
| (sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 9))
^ 0x20F7F3F9;
}
}
else {
curButtons = ((((sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 0xF0) << 12)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(0)] & 0xF0) << 8)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 0x6) << 7)
| ((sysPacket->rx[PSP_SYSCON_RX_DATA(0)] & 0xF) << 4)
| (sysPacket->rx[PSP_SYSCON_RX_DATA(1)] & 0x9))
^ 0x7F3F9)
| (g_ctrl.rawButtons & 0xFFF00000);
}
g_ctrl.rawButtons = curButtons;
if (sysPacket->tx[PSP_SYSCON_TX_CMD] == PSP_SYSCON_CMD_GET_ANALOG) {
analogY = sysPacket->rx[PSP_SYSCON_RX_DATA(1)];
analogX = sysPacket->rx[PSP_SYSCON_RX_DATA(0)];
}
else if (sysPacket->tx[PSP_SYSCON_TX_CMD] == PSP_SYSCON_CMD_GET_DIGITAL_KEY_ANALOG) {
analogY = sysPacket->rx[PSP_SYSCON_RX_DATA(3)];
analogX = sysPacket->rx[PSP_SYSCON_RX_DATA(2)];
}
else if (sysPacket->tx[PSP_SYSCON_TX_CMD] == PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY_ANALOG) {
analogY = sysPacket->rx[PSP_SYSCON_RX_DATA(5)];
analogX = sysPacket->rx[PSP_SYSCON_RX_DATA(4)];
}
else {
analogY = g_ctrl.analogY;
analogX = g_ctrl.analogX;
}
g_ctrl.analogX = analogX;
g_ctrl.analogY = analogY;
_sceCtrlUpdateButtons(curButtons, analogX, analogY);
if (g_ctrl.cancelIdleTimer == SCE_FALSE) {
newButtons = prevButtons ^ curButtons;
if ((curButtons & SCE_CTRL_HOLD) == 0) {
oneTimeIdleResetButtons = g_ctrl.oneTimeIdleResetButtons;
allTimeIdleResetButtons = g_ctrl.allTimeIdleResetButtons;
idleVal = g_ctrl.unHoldThreshold;
}
else {
oneTimeIdleResetButtons = g_ctrl.oneTimeIdleHoldModeResetButtons;
allTimeIdleResetButtons = g_ctrl.allTimeIdleHoldModeResetButtons;
idleVal = g_ctrl.holdThreshold;
}
oneTimeIdleResetButtons &= newButtons;
allTimeIdleResetButtons &= curButtons;
idleResetButtons = oneTimeIdleResetButtons | allTimeIdleResetButtons;
idleResetButtons &= g_ctrl.idleResetAllSupportedButtons;
if (idleResetButtons == 0) {
if (g_ctrl.samplingMode[USER_MODE] != SCE_CTRL_INPUT_DIGITAL_ONLY) {
aXCenterOffset = (u8)pspMax(analogX - CTRL_ANALOG_PAD_CENTER_VALUE,
-(analogX - CTRL_ANALOG_PAD_CENTER_VALUE));
aYCenterOffset = (u8)pspMax(analogY - CTRL_ANALOG_PAD_CENTER_VALUE,
-(analogY - CTRL_ANALOG_PAD_CENTER_VALUE));
aXCenterOffset = (aXCenterOffset == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ?
CTRL_ANALOG_PAD_CENTER_VALUE : aXCenterOffset;
aYCenterOffset = (aYCenterOffset == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ?
CTRL_ANALOG_PAD_CENTER_VALUE : aYCenterOffset;
if (aXCenterOffset >= idleVal || aYCenterOffset >= idleVal)
g_ctrl.cancelIdleTimer = SCE_TRUE;
}
}
else {
g_ctrl.cancelIdleTimer = SCE_TRUE;
}
}
sampling = ((g_ctrl.samplingMode[0] != 0) || (g_ctrl.samplingMode[1] != 0));
sampling = (g_ctrl.cableTypeReq != 0) ? (sampling | 2) : sampling;
if (sampling != g_ctrl.unk15 && (g_ctrl.sysconStatus.busy.intr2 == SCE_FALSE)) {
g_ctrl.sysconStatus.busy.intr2 = SCE_TRUE;
g_ctrl.sysPacket[1].tx[PSP_SYSCON_TX_CMD] = PSP_SYSCON_CMD_CTRL_ANALOG_XY_POLLING;
g_ctrl.sysPacket[1].tx[PSP_SYSCON_TX_LEN] = 3;
g_ctrl.sysPacket[1].tx[PSP_SYSCON_TX_DATA(0)] = sampling;
status = sceSysconCmdExecAsync(&g_ctrl.sysPacket[1], 0, _sceCtrlSysconCmdIntr2, NULL);
if (status < SCE_ERROR_OK)
g_ctrl.sysconStatus.busy.intr2 = SCE_FALSE;
}
/* Set the event flag to indicate a finished update interval. */
sceKernelSetEventFlag(g_ctrl.updateEventId, UPDATE_INTERRUPT_EVENT_FLAG_ON);
return SCE_ERROR_OK;
}
}
static s32 _sceCtrlSysconCmdIntr2(SceSysconPacket *packet, void *argp)
{
(void)packet;
(void)argp;
g_ctrl.cableTypeReq = 0;
g_ctrl.unk15 = g_ctrl.sysPacket[1].tx[PSP_SYSCON_TX_DATA(0)] & 0x1;
g_ctrl.sysconStatus.busy.intr2 = SCE_FALSE;
return SCE_ERROR_OK;
}
/*
* Update the internal controller button data buffers with the obtained
* raw button data from a SYSCON hardware register transfer. Furthermore,
* apply custom user settings to the button data.
*
* Returns 0.
*/
static s32 _sceCtrlUpdateButtons(u32 rawButtons, u8 aX, u8 aY)
{
SceCtrlData *ctrlUserBuf, *ctrlKernelBuf;
SceCtrlDataExt *ctrlUserBufExt, *ctrlKernelBufExt;
SceKernelButtonCallbackFunction buttonCallback;
u32 sysTimeLow;
u32 buttons, curButtons, prevButtons, pressedButtons;
u32 index;
u8 analogX, tmpAnalogX, tmpAnalogX2;
u8 analogY, tmpAnalogY, tmpAnalogY2;
u8 aXCenterOffset, aXCenterOffset2;
u8 aYCenterOffset, aYCenterOffset2;
u8 minIdleReset;
s32(*transferInputFunc)(void *, SceCtrlDataExt *);
s32 status;
s32 res;
u32 storeData;
/* Contains the real pressed buttons (received via SYSCON) and the
* custom button settings.
*/
u32 updatedButtons;
/* Records buttons which are currently not being pressed. */
u32 unpressedButtons;
/* Contains buttons which have a different state compared between
* the current frame and the last one. That means it includes the
* buttons which were pressed during the past frame but not during
* the current one or vice-versa.
*/
u32 changedButtons;
u32 uModeBtnEmulation, uModeBtnEmulationAll;
u32 kModeBtnEmulation, kModeBtnEmulationAll;
u32 numBufUpdates;
u8 rfEventMode, rfEventModeTimeLeft;
u32 i, j;
/* global pointer. */
u32 gp;
u8 check = 0;
sysTimeLow = sceKernelGetSystemTimeLow();
ctrlUserBuf = (SceCtrlData *)g_ctrl.userModeData.pCtrlInputBuffers[0] + g_ctrl.userModeData.curUpdatableBufIndex;
ctrlUserBuf->timeStamp = sysTimeLow;
ctrlKernelBuf = (SceCtrlData *)g_ctrl.kernelModeData.pCtrlInputBuffers[0] + g_ctrl.kernelModeData.curUpdatableBufIndex;
ctrlKernelBuf->timeStamp = sysTimeLow;
analogX = aX;
analogY = aY;
for (i = 0; i < CTRL_DATA_EMULATION_SLOTS; i++) {
if (g_ctrl.emulationData[i].uiAnalogMake > 0) {
g_ctrl.emulationData[i].uiAnalogMake--;
analogX = g_ctrl.emulationData[i].analogX;
analogY = g_ctrl.emulationData[i].analogY;
}
}
ctrlUserBuf->aX = analogX;
ctrlUserBuf->aY = analogY;
ctrlKernelBuf->aX = analogX;
ctrlKernelBuf->aY = analogY;
if (g_ctrl.samplingMode[USER_MODE] == SCE_CTRL_INPUT_DIGITAL_ONLY) {
ctrlUserBuf->aY = CTRL_ANALOG_PAD_CENTER_VALUE;
ctrlUserBuf->aX = CTRL_ANALOG_PAD_CENTER_VALUE;
}
if (g_ctrl.samplingMode[KERNEL_MODE] == SCE_CTRL_INPUT_DIGITAL_ONLY) {
ctrlKernelBuf->aY = CTRL_ANALOG_PAD_CENTER_VALUE;
ctrlKernelBuf->aX = CTRL_ANALOG_PAD_CENTER_VALUE;
}
tmpAnalogX = 0;
tmpAnalogY = 0;
for (i = 0; i < sizeof ctrlUserBuf->rsrv; i++)
ctrlUserBuf->rsrv[i] = 0;
for (i = 0; i < sizeof ctrlKernelBuf->rsrv; i++)
ctrlKernelBuf->rsrv[i] = 0;
/* Check for additionally registered input data transfers. */
for (i = 0; i < CTRL_NUM_EXTERNAL_INPUT_MODES; i++) {
if (g_ctrl.transferHandler[i] != NULL) {
ctrlKernelBufExt = (SceCtrlDataExt *)g_ctrl.kernelModeData.pCtrlInputBuffers[i + 1] + g_ctrl.kernelModeData.curUpdatableBufIndex;
ctrlKernelBufExt->timeStamp = sysTimeLow;
transferInputFunc = (g_ctrl.transferHandler[i]->copyInputData);
status = transferInputFunc(g_ctrl.extInputDataSource[i], ctrlKernelBufExt); // 0x00000F64
if (status < 0) {
for (j = 0; j < sizeof ctrlKernelBufExt->rsrv; j++)
ctrlKernelBufExt->rsrv[j] = 0;
ctrlKernelBufExt->timeStamp = 0;
ctrlKernelBufExt->buttons = 0;
ctrlKernelBufExt->DPadSenseA = 0;
ctrlKernelBufExt->DPadSenseB = 0;
ctrlKernelBufExt->GPadSenseA = 0;
ctrlKernelBufExt->GPadSenseB = 0;
ctrlKernelBufExt->AxisSenseA = 0;
ctrlKernelBufExt->AxisSenseB = 0;
ctrlKernelBufExt->TiltA = 0;
ctrlKernelBufExt->TiltB = 0;
ctrlKernelBufExt->aX = CTRL_ANALOG_PAD_CENTER_VALUE;
ctrlKernelBufExt->aY = CTRL_ANALOG_PAD_CENTER_VALUE;
ctrlKernelBufExt->rsrv[0] = -128;
ctrlKernelBufExt->rsrv[1] = -128;
}
else {
if (g_ctrl.cancelIdleTimer == SCE_FALSE) {
res = (ctrlKernelBufExt->buttons ^ g_ctrl.prevKernelButtons[i]) | ctrlKernelBufExt->buttons;
res &= 0x1FFFF;
g_ctrl.prevKernelButtons[i] = ctrlKernelBufExt->buttons;
if (res != 0)
g_ctrl.cancelIdleTimer = SCE_TRUE;
}
if (g_ctrl.cancelIdleTimer == SCE_FALSE && g_ctrl.samplingMode[USER_MODE] == SCE_CTRL_INPUT_DIGITAL_ANALOG) {
aXCenterOffset = pspMax(ctrlKernelBufExt->aX - CTRL_ANALOG_PAD_CENTER_VALUE,
-(ctrlKernelBufExt->aX - CTRL_ANALOG_PAD_CENTER_VALUE));
tmpAnalogX = aXCenterOffset;
aYCenterOffset = pspMax(ctrlKernelBufExt->aY - CTRL_ANALOG_PAD_CENTER_VALUE,
-(ctrlKernelBufExt->aY - CTRL_ANALOG_PAD_CENTER_VALUE));
tmpAnalogY = aYCenterOffset;
/*
* When the analog stick is released, it automatically returns to the
* center position. However, depending on where the stick is released,
* it may no not return to the exact center position. The guaranteed
* range for returning to the center when the stick is released is
* CTRL_ANALOG_PAD_CENTER_VALUE +/- CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN.
*/
minIdleReset = (g_ctrl.unHoldThreshold < CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN) ?
CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN : g_ctrl.unHoldThreshold;
aXCenterOffset = (tmpAnalogX == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ? CTRL_ANALOG_PAD_CENTER_VALUE :
aXCenterOffset;
aYCenterOffset = (tmpAnalogY == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ? CTRL_ANALOG_PAD_CENTER_VALUE :
aYCenterOffset;
aXCenterOffset2 = pspMax(ctrlKernelBufExt->rsrv[0] - CTRL_ANALOG_PAD_CENTER_VALUE,
-ctrlKernelBufExt->rsrv[0] + CTRL_ANALOG_PAD_CENTER_VALUE);
aYCenterOffset2 = pspMax(ctrlKernelBufExt->rsrv[1] - CTRL_ANALOG_PAD_CENTER_VALUE,
-ctrlKernelBufExt->rsrv[1] + CTRL_ANALOG_PAD_CENTER_VALUE);
aXCenterOffset2 = (aXCenterOffset2 == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ?
CTRL_ANALOG_PAD_CENTER_VALUE : aXCenterOffset2;
aYCenterOffset2 = (aYCenterOffset2 == (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) ?
CTRL_ANALOG_PAD_CENTER_VALUE : aYCenterOffset2;
if (aYCenterOffset >= minIdleReset || aXCenterOffset >= minIdleReset ||
aYCenterOffset2 >= minIdleReset || aXCenterOffset2 >= minIdleReset)
g_ctrl.cancelIdleTimer = SCE_TRUE;
}
}
ctrlUserBufExt = (SceCtrlDataExt *)g_ctrl.userModeData.pCtrlInputBuffers[i + 1] + g_ctrl.userModeData.curUpdatableBufIndex;
ctrlUserBufExt->timeStamp = ctrlKernelBufExt->timeStamp;
ctrlUserBufExt->buttons = ctrlKernelBufExt->buttons;
ctrlUserBufExt->aX = ctrlKernelBufExt->aX;
ctrlUserBufExt->aY = ctrlKernelBufExt->aY;
for (j = 0; j < sizeof ctrlUserBufExt->rsrv; j++)
ctrlUserBufExt->rsrv[j] = ctrlKernelBufExt->rsrv[j];
ctrlUserBufExt->DPadSenseA = ctrlKernelBufExt->DPadSenseA;
ctrlUserBufExt->DPadSenseB = ctrlKernelBufExt->DPadSenseB;
ctrlUserBufExt->GPadSenseA = ctrlKernelBufExt->GPadSenseA;
ctrlUserBufExt->GPadSenseB = ctrlKernelBufExt->GPadSenseB;
ctrlUserBufExt->AxisSenseA = ctrlKernelBufExt->AxisSenseA;
ctrlUserBufExt->AxisSenseB = ctrlKernelBufExt->AxisSenseB;
ctrlUserBufExt->TiltA = ctrlKernelBufExt->TiltA;
ctrlUserBufExt->TiltB = ctrlKernelBufExt->TiltB;
ctrlUserBufExt->buttons &= ~SCE_CTRL_INTERCEPTED;
ctrlUserBufExt->buttons &= g_ctrl.maskSupportButtons;
ctrlUserBufExt->buttons |= g_ctrl.maskApplyButtons;
if ((g_ctrl.unk768 >> i) == 1) {
buttons = ctrlKernelBufExt->buttons;
g_ctrl.emulationData[i + 1].uiButtonMake = 1;
kModeBtnEmulation = (buttons & 0xFFFFF0FF)
| (((buttons & 0x500) != 0) << 8)
| (((buttons & 0xA00) != 0) << 9);
uModeBtnEmulation = kModeBtnEmulation & g_ctrl.userModeButtons;
g_ctrl.emulationData[i + 1].userButtons = uModeBtnEmulation;
g_ctrl.emulationData[i + 1].kernelButtons = kModeBtnEmulation;
aXCenterOffset = pspMax(ctrlKernelBufExt->aX - CTRL_ANALOG_PAD_CENTER_VALUE,
-(ctrlKernelBufExt->aX - CTRL_ANALOG_PAD_CENTER_VALUE));
aYCenterOffset = pspMax(ctrlKernelBufExt->aY - CTRL_ANALOG_PAD_CENTER_VALUE,
-(ctrlKernelBufExt->aY - CTRL_ANALOG_PAD_CENTER_VALUE));
if (aXCenterOffset <= CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN &&
aYCenterOffset > CTRL_ANALOG_PAD_CENTER_POS_ERROR_MARGIN) {
check = 1;
tmpAnalogY = analogY & 0xFF;
tmpAnalogY -= CTRL_ANALOG_PAD_CENTER_VALUE;
tmpAnalogX -= CTRL_ANALOG_PAD_CENTER_VALUE;
}
}
}
}
if ((tmpAnalogX | tmpAnalogY) != 0) {
tmpAnalogX2 = tmpAnalogX + analogX;
storeData = 1;
if ((analogX - 65) < (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) {
analogX = CTRL_ANALOG_PAD_MAX_VALUE;
if ((analogY - 65) < (CTRL_ANALOG_PAD_CENTER_VALUE - 1)) {
analogX = CTRL_ANALOG_PAD_CENTER_VALUE;
analogY = CTRL_ANALOG_PAD_CENTER_VALUE;
tmpAnalogX2 = tmpAnalogX + analogX;
}
else {
storeData = 0; //simple check to not break the ASM code.
}
}
if (storeData)
analogX = CTRL_ANALOG_PAD_MAX_VALUE;
tmpAnalogY += analogY;
tmpAnalogX = pspMin(tmpAnalogX2, analogX);
if ((s8)tmpAnalogX2 < CTRL_ANALOG_PAD_MIN_VALUE)
tmpAnalogX = CTRL_ANALOG_PAD_MIN_VALUE;
analogY = CTRL_ANALOG_PAD_MAX_VALUE;
tmpAnalogY2 = pspMin(tmpAnalogY, analogY);
if ((s8)tmpAnalogY < CTRL_ANALOG_PAD_MIN_VALUE)
tmpAnalogY2 = CTRL_ANALOG_PAD_MIN_VALUE;
if (g_ctrl.samplingMode[USER_MODE] == SCE_CTRL_INPUT_DIGITAL_ANALOG) {
ctrlUserBuf->aX = tmpAnalogX;
ctrlUserBuf->aY = tmpAnalogY2;
}
if (g_ctrl.samplingMode[KERNEL_MODE] == SCE_CTRL_INPUT_DIGITAL_ANALOG) {
ctrlKernelBuf->aX = tmpAnalogX;
ctrlKernelBuf->aY = tmpAnalogY2;
}
}
/*
* Update the controller module's kernel controller data buffers.
*/
//index = SVALALIGN64(g_ctrl.userModeData.curUpdatableBufIndex + 1);
index = (g_ctrl.userModeData.curUpdatableBufIndex + 1) % CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
g_ctrl.userModeData.curUpdatableBufIndex = index;
/*
* In case we updated 64 internal buffers without reading from any updated buffer
* during this process we increase the index for the first unread updated buffer by 1
* to ensure that a consecutive read of 64 buffers will read from the latest updated 64
* internal buffers.
*/
if (index == g_ctrl.userModeData.firstUnReadUpdatedBufIndex)
g_ctrl.userModeData.firstUnReadUpdatedBufIndex = (index + 1) % CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
//index = SVALALIGN64(g_ctrl.kernelModeData.curUpdatableBufIndex + 1);
index = (g_ctrl.kernelModeData.curUpdatableBufIndex + 1) % CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
g_ctrl.kernelModeData.curUpdatableBufIndex = index;
if (index == g_ctrl.kernelModeData.firstUnReadUpdatedBufIndex)
g_ctrl.kernelModeData.firstUnReadUpdatedBufIndex = (index + 1) % CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
updatedButtons = rawButtons;
if (rawButtons & SCE_CTRL_HOLD)
updatedButtons &= CTRL_HARDWARE_IO_BUTTONS;
for (i = 0; i < CTRL_DATA_EMULATION_SLOTS; i++)
updatedButtons |= g_ctrl.emulationData[i].kernelButtons;
ctrlKernelBuf->buttons = updatedButtons;
/* Update the kernel latch data with the current button states. */
unpressedButtons = ~updatedButtons;
changedButtons = g_ctrl.prevModifiedButtons ^ updatedButtons;
pressedButtons = g_ctrl.kernelModeData.btnPress | updatedButtons;
g_ctrl.prevModifiedButtons = updatedButtons;
updatedButtons = rawButtons & g_ctrl.maskSupportButtons;
g_ctrl.kernelModeData.btnPress = pressedButtons;
g_ctrl.kernelModeData.btnRelease |= unpressedButtons;
g_ctrl.kernelModeData.btnMake |= (changedButtons & updatedButtons);
g_ctrl.kernelModeData.btnBreak |= (changedButtons & unpressedButtons);
g_ctrl.kernelModeData.readLatchCount++;
if (updatedButtons & SCE_CTRL_HOLD)
updatedButtons &= (SCE_CTRL_HOLD | SCE_CTRL_INTERCEPTED);
/*
* Apply custom emulation data of the digital pad to the transfered
* button data.
*/
uModeBtnEmulationAll = 0;
kModeBtnEmulationAll = 0;
for (i = 0; i < CTRL_DATA_EMULATION_SLOTS; i++) {
uModeBtnEmulation = g_ctrl.emulationData[i].userButtons;
kModeBtnEmulation = g_ctrl.emulationData[i].kernelButtons;
numBufUpdates = g_ctrl.emulationData[i].uiButtonMake;
uModeBtnEmulationAll |= uModeBtnEmulation;
kModeBtnEmulationAll |= kModeBtnEmulation;
if (numBufUpdates > 0) {
if (--numBufUpdates == 0) {
g_ctrl.emulationData[i].userButtons = 0;
g_ctrl.emulationData[i].userButtons = 0;
}
g_ctrl.emulationData[i].uiButtonMake = numBufUpdates;
}
}
updatedButtons |= uModeBtnEmulationAll;
gp = pspGetGp();
curButtons = kModeBtnEmulationAll | rawButtons;
prevButtons = g_ctrl.prevButtons;
g_ctrl.prevButtons = curButtons;
pressedButtons = curButtons ^ prevButtons;
/*
* Make sure we check for the call conditions of custom registered
* button callbacks and execute them if necessary. A button callback
* is executed when at least one of the specified callback buttons
* is pressed.
*/
for (i = 0; i < CTRL_BUTTON_CALLBACK_SLOTS; i++) {
if ((g_ctrl.buttonCallback[i].buttonMask & pressedButtons) != 0) {
if (g_ctrl.buttonCallback[i].callback != NULL) {
pspSetGp(g_ctrl.buttonCallback[i].gp);
buttonCallback = g_ctrl.buttonCallback[i].callback;
buttonCallback(curButtons, prevButtons, g_ctrl.buttonCallback[i].arg);
}
}
}
pspSetGp(gp);
/*
* Here, we check for rapid fire events belonging to buttons waiting
* for their execution.
*/
for (i = 0; i < CTRL_BUTTONS_RAPID_FIRE_SLOTS; i++) {
if (g_ctrl.rapidFire[i].uiMask != 0) {
pressedButtons = updatedButtons & g_ctrl.rapidFire[i].uiMask;
if (pressedButtons == g_ctrl.rapidFire[i].uiTrigger) {
rfEventModeTimeLeft = RF_EVENT_GET_APPLY_TIME_LEFT(g_ctrl.rapidFire[i].eventData) - 1;
rfEventMode = RF_EVENT_GET_MODE(g_ctrl.rapidFire[i].eventData);
if (rfEventMode != 0) {
if (rfEventMode == RAPID_FIRE_EVENT_BUTTONS_ON)
updatedButtons |= g_ctrl.rapidFire[i].uiTarget;
else
updatedButtons &= ~g_ctrl.rapidFire[i].uiTarget;
/*
* The apply time of one part of the rapid fire event (buttons turned
* either ON or OFF) has finished and now the second part of rapid fire
* event will be set. That means, for example, a button which was
* turned ON will now be turned OFF for the specified OFF time. Once
* this part is finished, the first part will be executed again.
*/
if (rfEventModeTimeLeft == 0) {
rfEventMode = (rfEventMode == RAPID_FIRE_EVENT_BUTTONS_ON) ? RAPID_FIRE_EVENT_BUTTONS_OFF :
RAPID_FIRE_EVENT_BUTTONS_ON;
rfEventModeTimeLeft = (rfEventMode == RAPID_FIRE_EVENT_BUTTONS_OFF) ?
g_ctrl.rapidFire[i].uiBreak :
g_ctrl.rapidFire[i].uiMake;
}
}
else {
rfEventModeTimeLeft = g_ctrl.rapidFire[i].uiDelay;
rfEventMode = RAPID_FIRE_EVENT_BUTTONS_ON;
}
g_ctrl.rapidFire[i].eventData = RF_EVENT_SET_MODE(rfEventMode) | rfEventModeTimeLeft;
}
else {
g_ctrl.rapidFire[i].eventData = 0;
}
}
}
/* Apply the custom button mask settings set by the user. */
updatedButtons &= g_ctrl.maskSupportButtons;
updatedButtons |= g_ctrl.maskApplyButtons;
if (updatedButtons & SCE_CTRL_HOLD) {
if (check == 0) {
if (uModeBtnEmulationAll != 0) {
updatedButtons = ((updatedButtons & g_ctrl.userModeButtons) != 0) ? (updatedButtons & ~SCE_CTRL_HOLD) :
updatedButtons;
}
}
else {
updatedButtons &= ~SCE_CTRL_HOLD;
}
}
changedButtons = updatedButtons ^ g_ctrl.userButtons;
if (updatedButtons & SCE_CTRL_HOLD) {
updatedButtons &= (SCE_CTRL_HOLD | SCE_CTRL_INTERCEPTED);
changedButtons = updatedButtons ^ g_ctrl.userButtons;
}
ctrlUserBuf->buttons = updatedButtons;
g_ctrl.userButtons = updatedButtons;
if (changedButtons & SCE_CTRL_HOLD)
g_ctrl.unk582 = g_ctrl.unk583;
if (g_ctrl.unk582 != 0) {
updatedButtons &= SCE_CTRL_INTERCEPTED;
g_ctrl.unk582--;
changedButtons = updatedButtons ^ g_ctrl.userButtons;
}
unpressedButtons = ~updatedButtons;
updatedButtons &= changedButtons;
pressedButtons = g_ctrl.userModeData.btnPress | updatedButtons;
/* Update the user mode latch data. */
g_ctrl.userModeData.btnRelease |= unpressedButtons;
g_ctrl.userModeData.btnBreak |= (unpressedButtons & changedButtons);
g_ctrl.userModeData.btnPress |= pressedButtons;
g_ctrl.userModeData.btnMake |= changedButtons;
g_ctrl.userModeData.readLatchCount++;
return SCE_ERROR_OK;
}
/*
* Read the internal controller data buffers and fill the passed data
* buffer with the obtained data.
*
* Returns the number of read internal controller data buffers.
*/
static s32 _sceCtrlReadBuf(SceCtrlDataExt *pData, u8 nBufs, u32 inputMode, u8 mode)
{
SceCtrlInternalData *intDataPtr;
SceCtrlDataExt *ctrlBuf;
s32 oldK1;
u32 i;
u32 buttons;
s8 bufIndex, startBufIndex;
s32 numReadIntBufs;
s32 status;
s32 intrState;
if (nBufs >= CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS)
return SCE_ERROR_INVALID_SIZE;
if (inputMode > CTRL_NUM_EXTERNAL_INPUT_MODES)
return SCE_ERROR_INVALID_VALUE;
if (inputMode != SCE_CTRL_EXTERNAL_INPUT_NONE && (mode & READ_BUFFER_POSITIVE))
return SCE_ERROR_NOT_SUPPORTED;
oldK1 = pspShiftK1();
/* Protect Kernel memory from User Mode. */
if (!pspK1PtrOk(pData)) {
pspSetK1(oldK1);
return SCE_ERROR_PRIV_REQUIRED;
}
if (pspK1IsUserMode())
intDataPtr = &g_ctrl.userModeData;
else
intDataPtr = &g_ctrl.kernelModeData;
if (inputMode != SCE_CTRL_EXTERNAL_INPUT_NONE && intDataPtr->pCtrlInputBuffers[inputMode] == NULL)
return SCE_ERROR_NOT_SUPPORTED;
/*
* Make sure we wait for the next update interval of the internal
* controller data buffers before reading them, in case the user
* used the "SceCtrlReadBuffer*()" functions to obtain button data.
* We do this to make sure the user obtains the newest updated button
* data and does not receive previously read old button data.
*/
if (mode & READ_BUFFER_POSITIVE) {
status = sceKernelWaitEventFlag(g_ctrl.updateEventId, UPDATE_INTERRUPT_EVENT_FLAG_ON, SCE_KERNEL_EW_OR, NULL,
NULL);
if (status < SCE_ERROR_OK) {
pspSetK1(oldK1);
return status;
}
intrState = sceKernelCpuSuspendIntr();
/*
* Clear the event flag so we can wait for the next finished update
* interval again.
*/
sceKernelClearEventFlag(g_ctrl.updateEventId, ~UPDATE_INTERRUPT_EVENT_FLAG_ON);
startBufIndex = intDataPtr->firstUnReadUpdatedBufIndex;
numReadIntBufs = intDataPtr->curUpdatableBufIndex - startBufIndex;
if (numReadIntBufs < 0)
numReadIntBufs += CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS;
intDataPtr->firstUnReadUpdatedBufIndex = intDataPtr->curUpdatableBufIndex;
if (nBufs < numReadIntBufs) {
startBufIndex = intDataPtr->curUpdatableBufIndex - nBufs;
startBufIndex = (startBufIndex < 0) ? startBufIndex + CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS : startBufIndex;
numReadIntBufs = nBufs;
}
}
else {
intrState = sceKernelCpuSuspendIntr();
/* Read input data from the last 'nBufs' updated buffers. */
bufIndex = intDataPtr->curUpdatableBufIndex;
startBufIndex = bufIndex;
startBufIndex = bufIndex - nBufs;
startBufIndex = (startBufIndex < 0) ? startBufIndex + CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS : startBufIndex;
numReadIntBufs = nBufs;
}
if (inputMode != SCE_CTRL_EXTERNAL_INPUT_NONE)
ctrlBuf = (SceCtrlDataExt *)intDataPtr->pCtrlInputBuffers[inputMode] + startBufIndex;
else
ctrlBuf = (SceCtrlDataExt *)((SceCtrlData *)intDataPtr->pCtrlInputBuffers[inputMode] + startBufIndex);
if (numReadIntBufs < 0) {
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return numReadIntBufs;
}
/*
* Read "nBufs" internal controller data buffers and obtain their data.
*/
while (nBufs-- > 0) {
pData->timeStamp = ctrlBuf->timeStamp;
buttons = ctrlBuf->buttons;
/* Ignore kernel mode buttons in user mode applications. */
if (pspK1IsUserMode())
buttons &= g_ctrl.userModeButtons;
/*
* Here, we decide whether the button data is represented in positive
* logic or negative logic. "Negative" functions instruct us to use
* negative logic.
*/
pData->buttons = (mode & PEEK_BUFFER_NEGATIVE) ? ~buttons : buttons;
pData->aX = ctrlBuf->aX;
pData->aY = ctrlBuf->aY;
pData->rX = 0;
pData->rY = 0;
if (mode < PEEK_BUFFER_POSITIVE_EXTRA) {
for (i = 0; i < sizeof pData->rsrv; i++)
pData->rsrv[i] = 0;
pData = (SceCtrlDataExt *)((SceCtrlData *)pData + 1);
}
/*
* We test if the data buffer used to obtain the internal button data
* is an extended data buffer and fill it accordingly.
*/
if (mode >= PEEK_BUFFER_POSITIVE_EXTRA) {
pData->rsrv[0] = 0;
pData->rsrv[1] = 0;
if (inputMode == SCE_CTRL_EXTERNAL_INPUT_NONE) {
pData->rX = CTRL_ANALOG_PAD_CENTER_VALUE;
pData->rY = CTRL_ANALOG_PAD_CENTER_VALUE;
pData->rsrv[2] = 0;
pData->rsrv[3] = 0;
pData->DPadSenseA = 0;
pData->DPadSenseB = 0;
pData->GPadSenseA = 0;
pData->GPadSenseB = 0;
pData->AxisSenseA = 0;
pData->AxisSenseB = 0;
pData->TiltA = 0;
pData->TiltB = 0;
}
else {
pData->rX = ctrlBuf->rX;
pData->rY = ctrlBuf->rY;
pData->rsrv[2] = ctrlBuf->rsrv[2];
pData->rsrv[2] = ctrlBuf->rsrv[3];
pData->DPadSenseA = ctrlBuf->DPadSenseA;
pData->DPadSenseB = ctrlBuf->DPadSenseB;
pData->GPadSenseA = ctrlBuf->GPadSenseA;
pData->GPadSenseB = ctrlBuf->GPadSenseB;
pData->AxisSenseA = ctrlBuf->AxisSenseA;
pData->AxisSenseB = ctrlBuf->AxisSenseB;
pData->TiltA = ctrlBuf->TiltA;
pData->TiltB = ctrlBuf->TiltB;
}
pData += 1;
}
startBufIndex++;
if (startBufIndex == CTRL_NUM_INTERNAL_CONTROLLER_BUFFERS)
startBufIndex = 0;
if (inputMode == SCE_CTRL_EXTERNAL_INPUT_NONE)
ctrlBuf = (SceCtrlDataExt *)((SceCtrlData *)intDataPtr->pCtrlInputBuffers[inputMode] + startBufIndex);
else
ctrlBuf = (SceCtrlDataExt *)intDataPtr->pCtrlInputBuffers[inputMode] + startBufIndex;
}
sceKernelCpuResumeIntr(intrState);
pspSetK1(oldK1);
return numReadIntBufs;
}
s32 _sceCtrlModuleStart(s32 argc, void *argp)
{
(void)argc;
(void)argp;
sceCtrlInit();
return SCE_KERNEL_RESIDENT;
}
s32 _sceCtrlModuleRebootBefore(s32 argc, void *argp)
{
(void)argc;
(void)argp;
sceCtrlEnd();
return SCE_KERNEL_STOP_SUCCESS;
}
You can’t perform that action at this time.