summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Roncace <me@caseif.net>2026-02-01 20:33:08 -0500
committerGitHub <noreply@github.com>2026-02-01 17:33:08 -0800
commitf5dbf1d8276b249b114b2ed08f0f7b095911e97c (patch)
tree8bec854a5c2f0e57fb15839bcf822a12cb296d75 /src
parent21de544196bdc235b75fc1e51a1c395b806a7c59 (diff)
Revolution WPAD work (#3078)
* WPAD mostly matching, likely equivalent * Implement WPADEncrypt (mostly taken from SMG1 decomp) * Implement WPADHidParser * Add wpad_debug_msg stub * Fix WUD file paths in splits * Fix WPAD regressions in Shield/ShieldD
Diffstat (limited to 'src')
-rw-r--r--src/revolution/homebuttonLib/HBMController.cpp24
-rw-r--r--src/revolution/os/OSStateTM.c4
-rw-r--r--src/revolution/sc/scapi.c24
-rw-r--r--src/revolution/vi/__vi.h2
-rw-r--r--src/revolution/vi/vi.c13
-rw-r--r--src/revolution/wpad/WPAD.c2583
-rw-r--r--src/revolution/wpad/WPADEncrypt.c265
-rw-r--r--src/revolution/wpad/WPADHIDParser.c1667
-rw-r--r--src/revolution/wpad/WPADMem.c3
-rw-r--r--src/revolution/wpad/__wpad.h460
-rw-r--r--src/revolution/wpad/wpad_debug_msg.c5
-rw-r--r--src/revolution/wud/WUD.c (renamed from src/revolution/wpad/WUD.c)14
-rw-r--r--src/revolution/wud/__wud.h (renamed from src/revolution/wpad/__wud.h)1
-rw-r--r--src/revolution/wud/debug_msg.c6
14 files changed, 4657 insertions, 414 deletions
diff --git a/src/revolution/homebuttonLib/HBMController.cpp b/src/revolution/homebuttonLib/HBMController.cpp
index 207ee57130..a41bcfdf04 100644
--- a/src/revolution/homebuttonLib/HBMController.cpp
+++ b/src/revolution/homebuttonLib/HBMController.cpp
@@ -126,43 +126,43 @@ namespace homebutton {
u32 t = con->kpad->ex_status.cl.trig;
u32 r = con->kpad->ex_status.cl.release;
- if (h & WPAD_BUTTON_CL_A) {
+ if (h & WPAD_CL_BUTTON_A) {
mHBController.hold |= WPAD_BUTTON_A;
}
- if (t & WPAD_BUTTON_CL_A) {
+ if (t & WPAD_CL_BUTTON_A) {
mHBController.trig |= WPAD_BUTTON_A;
}
- if (r & WPAD_BUTTON_CL_A) {
+ if (r & WPAD_CL_BUTTON_A) {
mHBController.release |= WPAD_BUTTON_A;
}
- if (h & WPAD_BUTTON_CL_PLUS) {
+ if (h & WPAD_CL_BUTTON_PLUS) {
mHBController.hold |= WPAD_BUTTON_PLUS;
}
- if (t & WPAD_BUTTON_CL_PLUS) {
+ if (t & WPAD_CL_BUTTON_PLUS) {
mHBController.trig |= WPAD_BUTTON_PLUS;
}
- if (r & WPAD_BUTTON_CL_PLUS) {
+ if (r & WPAD_CL_BUTTON_PLUS) {
mHBController.release |= WPAD_BUTTON_PLUS;
}
- if (h & WPAD_BUTTON_CL_MINUS) {
+ if (h & WPAD_CL_BUTTON_MINUS) {
mHBController.hold |= WPAD_BUTTON_MINUS;
}
- if (t & WPAD_BUTTON_CL_MINUS) {
+ if (t & WPAD_CL_BUTTON_MINUS) {
mHBController.trig |= WPAD_BUTTON_MINUS;
}
- if (r & WPAD_BUTTON_CL_MINUS) {
+ if (r & WPAD_CL_BUTTON_MINUS) {
mHBController.release |= WPAD_BUTTON_MINUS;
}
- if (h & WPAD_BUTTON_CL_HOME) {
+ if (h & WPAD_CL_BUTTON_HOME) {
mHBController.hold |= WPAD_BUTTON_HOME;
}
- if (t & WPAD_BUTTON_CL_HOME) {
+ if (t & WPAD_CL_BUTTON_HOME) {
mHBController.trig |= WPAD_BUTTON_HOME;
}
- if (r & WPAD_BUTTON_CL_HOME) {
+ if (r & WPAD_CL_BUTTON_HOME) {
mHBController.release |= WPAD_BUTTON_HOME;
}
}
diff --git a/src/revolution/os/OSStateTM.c b/src/revolution/os/OSStateTM.c
index 3961ff7d98..a81de612cf 100644
--- a/src/revolution/os/OSStateTM.c
+++ b/src/revolution/os/OSStateTM.c
@@ -210,10 +210,6 @@ s32 __OSUnRegisterStateEvent(void) {
return ret;
}
-void ACRWriteReg(u32 param_0, u32 param_1) {
- __IPCRegs[param_0 >> 2] = param_1;
-}
-
// NONMATCHING - extra branch
static int AccessVIDimRegs(void) {
int res;
diff --git a/src/revolution/sc/scapi.c b/src/revolution/sc/scapi.c
index 9aa57e7ec1..3acfef055f 100644
--- a/src/revolution/sc/scapi.c
+++ b/src/revolution/sc/scapi.c
@@ -121,3 +121,27 @@ u32 SCGetCounterBias(void) {
return bias;
}
+
+u8 SCGetWpadSensorBarPosition(void) {
+ // NONMATCHING
+}
+
+u8 SCGetWpadMotorMode(void) {
+ // NONMATCHING
+}
+
+u8 SCGetWpadSpeakerVolume(void) {
+ // NONMATCHING
+}
+
+u8 SCGetBtDpdSensibility(void) {
+ // NONMATCHING
+}
+
+BOOL SCSetWpadSpeakerVolume(u8 volume) {
+ // NONMATCHING
+}
+
+BOOL SCSetWpadMotorMode(u8 mode) {
+ // NONMATCHING
+}
diff --git a/src/revolution/vi/__vi.h b/src/revolution/vi/__vi.h
index e061de3369..1411ca9294 100644
--- a/src/revolution/vi/__vi.h
+++ b/src/revolution/vi/__vi.h
@@ -17,6 +17,8 @@ void __VIInit(VITVMode mode);
void __VISetAdjustingValues(s16 x, s16 y);
void __VIGetAdjustingValues(s16* x, s16* y);
void __VIGetCurrentPosition(s16* x, s16* y);
+BOOL __VIResetSIIdle();
+BOOL __VIResetRFIdle();
BOOL __VIResetDev0Idle();
/* vi3in1.c */
diff --git a/src/revolution/vi/vi.c b/src/revolution/vi/vi.c
index 057ba805b4..647bbec498 100644
--- a/src/revolution/vi/vi.c
+++ b/src/revolution/vi/vi.c
@@ -1682,8 +1682,12 @@ BOOL VIEnableDimming(BOOL enable) {
return old;
}
-void VIResetDimmingCount() {
- __VIResetDev0Idle();
+BOOL VIResetDimmingCount() {
+ return __VIResetDev0Idle();
+}
+
+BOOL VIResetRFIdle() {
+ return __VIResetRFIdle();
}
BOOL VIEnableDVDStopMotor(BOOL enable) {
@@ -1697,6 +1701,11 @@ BOOL __VIResetSIIdle() {
return TRUE;
}
+BOOL __VIResetRFIdle() {
+ __VIDimmingFlag_RF_IDLE = 0;
+ return TRUE;
+}
+
BOOL __VIResetDev0Idle() {
__VIDimmingFlag_DEV_IDLE[0] = 0;
return TRUE;
diff --git a/src/revolution/wpad/WPAD.c b/src/revolution/wpad/WPAD.c
index bdd1531617..6f01d6e459 100644
--- a/src/revolution/wpad/WPAD.c
+++ b/src/revolution/wpad/WPAD.c
@@ -1,25 +1,1843 @@
-#include <revolution/os.h>
#include <revolution/wpad.h>
-#include <revolution/wpad/wud.h>
-
+#include <revolution/wpad/__wpad.h>
+
+#include <revolution/wud/WUD.h>
+#include <revolution/dvd.h>
+#include <revolution/sc.h>
+#include <revolution/vi.h>
+#include <revolution/wpad/bte.h>
+#include <cstdio>
#include <cstring>
-#include "__wpad.h"
+extern volatile BOOL __OSIsReturnToIdle;
+
+//TODO: this apparently should be aligned to 32 bytes, but
+// adding ATTRIBUTE_ALIGN breaks codegen in WPADInit
+WPADControlBlock _wpd[WPAD_MAX_CONTROLLERS];
+WPADControlBlock* _wpdcb[WPAD_MAX_CONTROLLERS];
+
+u8 _sleepTime;
+u8 _dpdSensitivity;
+u8 _sensorBarPos;
+BOOL _rumble;
+u8 _speakerVolume;
+u8 _scFlush;
+u8 _gametype;
+u16 _gameTitle[17];
+const char* _gamecode;
+
+s8 _dev_handle_index[16];
+u8 _chan_active_state[WPAD_MAX_CONTROLLERS];
+OSAlarm _managerAlarm;
+
+DVDDiskID _diskId;
+
+static u8 _scSetting;
+static vu8 _shutdown;
+static s8 _afhChannel;
+static u8 _regShutdown = 0;
+
+static u16 _senseCnt = 0;
+static u8 _checkCnt = 0;
+static u8 _extCnt = 0;
+static u16 _afhCnt = 0;
+
+static u8 _rumbleCnt[WPAD_MAX_CONTROLLERS] = {0, 0, 0, 0};
+
+static s8 _infRes[4];
+
+static BOOL _initialized;
+static BOOL _startup = FALSE;
+static int _recFlag = -1;
+static int _recCnt = 0;
+
+static const char* __WPADVersion = "<< RVL_SDK - WPAD \trelease build: Oct 3 2006 03:58:38 (0x4200_60422) >>";
+
+#define WPAD_DEFAULT_ACC_DIFF_COUNT_THRESHOLD (u16)(6)
+#define WPAD_DEFAULT_ACC_HYST_COUNT_THRESHOLD (u16)(30)
+
+#define WPAD_DEFAULT_DPD_DIFF_COUNT_THRESHOLD (u16)(4)
+#define WPAD_DEFAULT_DPD_HYST_COUNT_THRESHOLD (u16)(30)
+
+static u16 __WPAD_acc_diff_count_threshold = WPAD_DEFAULT_ACC_DIFF_COUNT_THRESHOLD;
+static u16 __WPAD_dpd_diff_count_threshold = WPAD_DEFAULT_DPD_DIFF_COUNT_THRESHOLD;
+
+static u16 __WPAD_acc_hyst_count_threshold = WPAD_DEFAULT_ACC_HYST_COUNT_THRESHOLD;
+static u16 __WPAD_dpd_hyst_count_threshold = WPAD_DEFAULT_DPD_HYST_COUNT_THRESHOLD;
+
+static OSShutdownFunctionInfo ShutdownFunctionInfo = {OnShutdown, 127};
+
+extern void DEBUGPrint(const char*, ...);
+
+static void __ClearControlBlock(s32 chan);
+
+BOOL OnShutdown(BOOL final, u32 event) {
+ s32 i;
+ BOOL ret;
+ s32 status;
+
+ ret = FALSE;
+ status = WUDGetStatus();
+
+ if (!final) {
+ if (status == 2 || status == 3) {
+ switch (event) {
+ case 0:
+ case 2:
+ case 3:
+ if (!_shutdown) {
+ _shutdown = TRUE;
+ WUDSetVisibility(0, 0);
+ for (i = 10; i < 14; i++) {
+ memset(&_scArray.info[i], 0, sizeof(_scArray.info[i]));
+ }
+ OSCancelAlarm(&_managerAlarm);
+ WUDSetHidRecvCallback(NULL);
+ WUDShutdown();
+ }
+ ret = FALSE;
+ break;
+ case 1:
+ case 4:
+ case 5:
+ case 6:
+ if (!_shutdown) {
+ _shutdown = TRUE;
+ BTA_DmSendHciReset();
+ OSCancelAlarm(&_managerAlarm);
+ WUDSetHidRecvCallback(NULL);
+ WUDShutdown();
+ }
+ ret = FALSE;
+ break;
+ }
+ } else if (status == 4 || status == 1) {
+ ret = FALSE;
+ } else if (status == 0) {
+ ret = TRUE;
+ }
+ } else {
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+s32 WPADiGetStatus(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ s32 status;
+
+ enable = OSDisableInterrupts();
+ status = p_wpd->status;
+ OSRestoreInterrupts(enable);
+
+ return status;
+}
+
+BOOL __SetSensorBarPower(BOOL flag) {
+ u32 reg;
+ u32 regBak;
+ BOOL enable;
+ BOOL result;
+
+ enable = OSDisableInterrupts();
+
+ regBak = ACRReadReg(0xC0);
+
+ if (flag) {
+ reg = regBak | 0x100;
+ } else {
+ reg = regBak & ~0x100;
+ }
+
+ ACRWriteReg(0xC0, reg);
+ result = (regBak & 0x100) ? TRUE : FALSE;
+ OSRestoreInterrupts(enable);
+ return result;
+}
+
+static u8 __GetDpdSensitivity() {
+ u8 level;
+
+ level = (u8)SCGetBtDpdSensibility();
+ if (level < 1) {
+ level = 1;
+ }
+ if (level > 5) {
+ level = 5;
+ }
+
+ return level;
+}
+
+static u8 __GetSensorBarPosition() {
+ u8 pos;
+
+ if (1 == SCGetWpadSensorBarPosition()) {
+ pos = WPAD_SENSOR_BAR_POS_TOP;
+ } else {
+ pos = WPAD_SENSOR_BAR_POS_BOTTOM;
+ }
+ return pos;
+}
+
+static BOOL __GetMotorMode() {
+ BOOL rumble;
+
+ if (1 == SCGetWpadMotorMode()) {
+ rumble = TRUE;
+ } else {
+ rumble = FALSE;
+ }
+ return rumble;
+}
+
+static u8 __ClampSpeakerVolume(u8 vol) {
+ u8 v = vol;
+
+ if (vol < 0) {
+ v = 0;
+ }
+ if (vol > 127) {
+ v = 127;
+ }
+
+ return v;
+}
+
+static u8 __GetSpeakerVolume() {
+ u8 vol;
+ vol = SCGetWpadSpeakerVolume();
+ vol = __ClampSpeakerVolume(vol);
+ return vol;
+}
+
+void WPADiManageHandler(OSAlarm*, OSContext*) {
+ s32 chan;
+ s32 status;
+ BOOL sendCmd;
+
+ status = WPADGetStatus();
+
+ if (status != WPAD_STATE_SETUP) {
+ return;
+ }
+
+ for (chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++) {
+ sendCmd = FALSE;
+ if (_extCnt == 5) {
+ sendCmd |= WPADiProcessExtCommand(chan);
+ }
+ sendCmd |= WPADiProcessCommand(chan);
+
+ WPADiRumbleMotor(chan, sendCmd);
+
+ if (_checkCnt == 5) {
+ WPADiCheckContInputs(chan);
+ }
+
+ if (_senseCnt == 10) {
+ WPADiRadioSensitivity(chan);
+ }
+ }
+
+ if (_afhCnt == 60000) {
+ WPADiAfh();
+ }
+
+ _senseCnt = (u16)((_senseCnt == 10) ? 0 : _senseCnt + 1);
+ _checkCnt = (u8)((_checkCnt == 5) ? 0 : _checkCnt + 1);
+ _extCnt = (u16)((_extCnt == 5) ? 0 : _extCnt + 1);
+ _afhCnt = (u16)((_afhCnt == 60000) ? 0 : _afhCnt + 1);
+
+ WPADiContMapTableUpdate();
+ WPADiGetScSettings();
+ BTA_HhGetAclQueueInfo();
+}
+
+u8 __WPADiManageHandlerStack[4096] ATTRIBUTE_ALIGN(32);
+
+void WPADiManageHandler0(OSAlarm* alarm, OSContext* context) {
+ OSSwitchFiberEx((u32)alarm, (u32)context, 0, 0, (u32)WPADiManageHandler, (u32)(__WPADiManageHandlerStack + sizeof(__WPADiManageHandlerStack)));
+}
+
+inline void WPADiInitSub() {
+ s32 i;
+
+ __SetSensorBarPower(TRUE);
+
+ for (i = 0; i < 16; i++) {
+ _dev_handle_index[i] = -1;
+ }
+
+ //TODO: this gets placed in .data incorrectly with the inline keyword,
+ // might be fixed when we figure out -ipa program
+ DEBUGPrint("WPADInit()\n");
+
+ for (i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
+ _wpdcb[i] = &_wpd[i];
+ _chan_active_state[i] = 0;
+ _wpdcb[i]->connectCallback = NULL;
+
+ __ClearControlBlock(i);
+ OSInitThreadQueue(&_wpd[i].threadQueue);
+ }
+
+ _sleepTime = 5;
+ _gamecode = OSGetAppGamename();
+ _gametype = OSGetAppType();
+ _dpdSensitivity = __GetDpdSensitivity();
+ _sensorBarPos = __GetSensorBarPosition();
+ _rumble = __GetMotorMode();
+ _speakerVolume = __GetSpeakerVolume();
+
+ WUDSetHidConnCallback(WPADiConnCallback);
+ WUDSetHidRecvCallback(WPADiRecvCallback);
+
+ _senseCnt = 0;
+ _checkCnt = 0;
+ _extCnt = 0;
+ _afhCnt = 0;
+ _rumbleCnt[0] = _rumbleCnt[1] = _rumbleCnt[2] = _rumbleCnt[3] = 0;
+
+ OSCreateAlarm(&_managerAlarm);
+ OSSetPeriodicAlarm(&_managerAlarm, __OSGetSystemTime(), OSMillisecondsToTicks(1),
+ WPADiManageHandler0);
+
+ _shutdown = 0;
+ _scFlush = 0;
+ _scSetting = 1;
+ _afhChannel = -1;
+
+ OSRegisterVersion(__WPADVersion);
+}
+
+void WPADInit(void) {
+ BOOL result;
+
+ if (_regShutdown == 0) {
+ OSRegisterShutdownFunction(&ShutdownFunctionInfo);
+ _regShutdown = 1;
+ }
+
+ result = WUDInit();
+
+ if (result) {
+ WPADiInitSub();
+ }
+}
+
+void WPADiRadioSensitivity(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u32 packet = 2;
+ u16 rs;
+
+ rs = (u16)(p_wpd->radioSensitivity * (10 - 1));
+ rs += (u16)((p_wpd->packetCnt * 100) / packet);
+ rs /= 10;
+ rs = (u16)((rs > 100) ? 100 : rs);
+
+ p_wpd->radioSensitivity = (u8)rs;
+ p_wpd->packetCnt = 0;
+
+ if (p_wpd->radioQuality) {
+ if (rs > 85) {
+ p_wpd->radioQuality = 0;
+ p_wpd->radioQualityOkMs = 0;
+ } else if (rs > 80) {
+ p_wpd->radioQualityOkMs++;
+ if (p_wpd->radioQualityOkMs >= 20) {
+ p_wpd->radioQuality = 0;
+ p_wpd->radioQualityOkMs = 0;
+ }
+ }
+ } else {
+ if (rs < 75) {
+ p_wpd->radioQuality = 1;
+ p_wpd->radioQualityOkMs = 0;
+ } else if (rs < 80) {
+ p_wpd->radioQualityOkMs++;
+ if (p_wpd->radioQualityOkMs >= 1) {
+ p_wpd->radioQuality = 1;
+ p_wpd->radioQualityOkMs = 0;
+ }
+ }
+ }
+}
+
+BOOL WPADiIsCoreFormat(u32 fmt) {
+ if (fmt == WPAD_FMT_CORE_BTN || fmt == WPAD_FMT_CORE_BTN_ACC || fmt == WPAD_FMT_CORE_BTN_ACC_DPD) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+BOOL WPADiIsFsFormat(u32 fmt) {
+ if (fmt == WPAD_FMT_FS_BTN || fmt == WPAD_FMT_FS_BTN_ACC || fmt == WPAD_FMT_FS_BTN_ACC_DPD) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+BOOL WPADiIsClFormat(u32 fmt) {
+ if (fmt == WPAD_FMT_CLASSIC_BTN || fmt == WPAD_FMT_CLASSIC_BTN_ACC || fmt == WPAD_FMT_CLASSIC_BTN_ACC_DPD) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static u8 IsButtonChanged(u16 curr, u16 prev) {
+ return (u8)((curr != prev) ? 1 : 0);
+}
+
+static u8 IsAnalogChanged(s32 curr, s32 prev, s32 threshold) {
+ s32 diff = ((curr - prev) < 0) ? prev - curr : curr - prev;
+ return (u8)((diff > threshold) ? 1 : 0);
+}
+
+BOOL IsControllerDataChanged(WPADControlBlock* p_wpd, void* p_curr, void* p_prev) {
+ u32 fmt;
+ u8 mode, result = 0;
+ int i;
+
+ mode = p_wpd->devMode;
+ fmt = p_wpd->dataFormat;
+
+ if (WPADiIsCoreFormat(fmt)) {
+ WPADStatus* curr = (WPADStatus*)p_curr;
+ WPADStatus* prev = (WPADStatus*)p_prev;
+ result |= IsButtonChanged(curr->button, prev->button);
+ if (curr->err == WPAD_ERR_OK && prev->err == WPAD_ERR_OK) {
+ if (IsAnalogChanged((s32)(curr->accX), (s32)(prev->accX), 12) | IsAnalogChanged((s32)(curr->accY), (s32)(prev->accY), 12) |
+ IsAnalogChanged((s32)(curr->accZ), (s32)(prev->accZ), 12)) {
+ DIFF_COUNT_ACC(p_wpd)++;
+ if (DIFF_COUNT_ACC(p_wpd) > __WPAD_acc_diff_count_threshold) {
+ DIFF_COUNT_ACC(p_wpd) = 0;
+ HYST_COUNT_ACC(p_wpd) = 0;
+ result |= 1;
+ }
+
+ } else {
+ HYST_COUNT_ACC(p_wpd) = (u16)((HYST_COUNT_ACC(p_wpd) + 1) % __WPAD_acc_hyst_count_threshold);
+ if (HYST_COUNT_ACC(p_wpd) == __WPAD_acc_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_ACC(p_wpd) > 0) {
+ DIFF_COUNT_ACC(p_wpd)--;
+ }
+ }
+ }
+
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; i++) {
+ if (IsAnalogChanged((s32)(curr->obj[i].x), (s32)(prev->obj[i].x), 2) |
+ IsAnalogChanged((s32)(curr->obj[i].y), (s32)(prev->obj[i].y), 2)) {
+ DIFF_COUNT_DPD(p_wpd)++;
+ if (DIFF_COUNT_DPD(p_wpd) > __WPAD_dpd_diff_count_threshold) {
+ DIFF_COUNT_DPD(p_wpd) = 0;
+ result |= 1;
+ }
+ } else {
+ HYST_COUNT_DPD(p_wpd) = (u16)((HYST_COUNT_DPD(p_wpd) + 1) % __WPAD_dpd_hyst_count_threshold);
+ if (HYST_COUNT_DPD(p_wpd) == __WPAD_dpd_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_DPD(p_wpd) > 0) {
+ DIFF_COUNT_DPD(p_wpd)--;
+ }
+ }
+ }
+ }
+ }
+
+ } else if (WPADiIsFsFormat(fmt)) {
+ WPADFSStatus* curr = (WPADFSStatus*)p_curr;
+ WPADFSStatus* prev = (WPADFSStatus*)p_prev;
+
+ result |= IsButtonChanged(curr->base.button, prev->base.button);
+ if (curr->base.err == WPAD_ERR_OK && prev->base.err == WPAD_ERR_OK) {
+ if (IsAnalogChanged((s32)(curr->base.accX), (s32)(prev->base.accX), 12) | IsAnalogChanged((s32)(curr->base.accY), (s32)(prev->base.accY), 12) |
+ IsAnalogChanged((s32)(curr->base.accZ), (s32)(prev->base.accZ), 12)) {
+ DIFF_COUNT_ACC(p_wpd)++;
+ if (DIFF_COUNT_ACC(p_wpd) > __WPAD_acc_diff_count_threshold) {
+ DIFF_COUNT_ACC(p_wpd) = 0;
+ HYST_COUNT_ACC(p_wpd) = 0;
+ result |= 1;
+ }
+
+ } else {
+ HYST_COUNT_ACC(p_wpd) = (u16)((HYST_COUNT_ACC(p_wpd) + 1) % __WPAD_acc_hyst_count_threshold);
+ if (HYST_COUNT_ACC(p_wpd) == __WPAD_acc_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_ACC(p_wpd) > 0) {
+ DIFF_COUNT_ACC(p_wpd)--;
+ }
+ }
+ }
+
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; i++) {
+ if (IsAnalogChanged((s32)(curr->base.obj[i].x), (s32)(prev->base.obj[i].x), 2) |
+ IsAnalogChanged((s32)(curr->base.obj[i].y), (s32)(prev->base.obj[i].y), 2)) {
+ DIFF_COUNT_DPD(p_wpd)++;
+ if (DIFF_COUNT_DPD(p_wpd) > __WPAD_dpd_diff_count_threshold) {
+ DIFF_COUNT_DPD(p_wpd) = 0;
+ result |= 1;
+ }
+ } else {
+ HYST_COUNT_DPD(p_wpd) = (u16)((HYST_COUNT_DPD(p_wpd) + 1) % __WPAD_dpd_hyst_count_threshold);
+ if (HYST_COUNT_DPD(p_wpd) == __WPAD_dpd_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_DPD(p_wpd) > 0) {
+ DIFF_COUNT_DPD(p_wpd)--;
+ }
+ }
+ }
+ }
+
+ if (IsAnalogChanged((s32)(curr->fsAccX), (s32)(prev->fsAccX), 12) | IsAnalogChanged((s32)(curr->fsAccY), (s32)(prev->fsAccY), 12) |
+ IsAnalogChanged((s32)(curr->fsAccZ), (s32)(prev->fsAccZ), 12)) {
+ DIFF_COUNT_FS_ACC(p_wpd)++;
+ if (DIFF_COUNT_FS_ACC(p_wpd) > __WPAD_acc_diff_count_threshold) {
+ DIFF_COUNT_FS_ACC(p_wpd) = 0;
+ HYST_COUNT_FS_ACC(p_wpd) = 0;
+ result |= 1;
+ }
+
+ } else {
+ HYST_COUNT_FS_ACC(p_wpd) = (u16)((HYST_COUNT_FS_ACC(p_wpd) + 1) % __WPAD_acc_hyst_count_threshold);
+ if (HYST_COUNT_FS_ACC(p_wpd) == __WPAD_acc_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_FS_ACC(p_wpd) > 0) {
+ DIFF_COUNT_FS_ACC(p_wpd)--;
+ }
+ }
+ }
+
+ result |= IsAnalogChanged((s32)(curr->fsStickX), (s32)(prev->fsStickX), 1);
+ result |= IsAnalogChanged((s32)(curr->fsStickY), (s32)(prev->fsStickY), 1);
+ }
+ } else if (WPADiIsClFormat(fmt)) {
+ WPADCLStatus* curr = (WPADCLStatus*)p_curr;
+ WPADCLStatus* prev = (WPADCLStatus*)p_prev;
+ s32 lstk;
+ s32 rstk;
+ s32 trig;
+
+ switch (mode) {
+ case 1:
+ lstk = 16;
+ rstk = 32;
+ trig = 8;
+ break;
+ case 3:
+ lstk = 4;
+ rstk = 4;
+ trig = 1;
+ break;
+ default:
+ lstk = 1;
+ rstk = 1;
+ trig = 1;
+ break;
+ }
+
+ result |= IsButtonChanged(curr->base.button, prev->base.button);
+ if (curr->base.err == WPAD_ERR_OK && prev->base.err == WPAD_ERR_OK) {
+ if (IsAnalogChanged((s32)(curr->base.accX), (s32)(prev->base.accX), 12) | IsAnalogChanged((s32)(curr->base.accY), (s32)(prev->base.accY), 12) |
+ IsAnalogChanged((s32)(curr->base.accZ), (s32)(prev->base.accZ), 12)) {
+ DIFF_COUNT_ACC(p_wpd)++;
+ if (DIFF_COUNT_ACC(p_wpd) > __WPAD_acc_diff_count_threshold) {
+ DIFF_COUNT_ACC(p_wpd) = 0;
+ HYST_COUNT_ACC(p_wpd) = 0;
+ result |= 1;
+ }
+
+ } else {
+ HYST_COUNT_ACC(p_wpd) = (u16)((HYST_COUNT_ACC(p_wpd) + 1) % __WPAD_acc_hyst_count_threshold);
+ if (HYST_COUNT_ACC(p_wpd) == __WPAD_acc_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_ACC(p_wpd) > 0) {
+ DIFF_COUNT_ACC(p_wpd)--;
+ }
+ }
+ }
+
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; i++) {
+ if (IsAnalogChanged((s32)(curr->base.obj[i].x), (s32)(prev->base.obj[i].x), 2) |
+ IsAnalogChanged((s32)(curr->base.obj[i].y), (s32)(prev->base.obj[i].y), 2)) {
+ DIFF_COUNT_DPD(p_wpd)++;
+ if (DIFF_COUNT_DPD(p_wpd) > __WPAD_dpd_diff_count_threshold) {
+ DIFF_COUNT_DPD(p_wpd) = 0;
+ result |= 1;
+ }
+ } else {
+ HYST_COUNT_DPD(p_wpd) = (u16)((HYST_COUNT_DPD(p_wpd) + 1) % __WPAD_dpd_hyst_count_threshold);
+ if (HYST_COUNT_DPD(p_wpd) == __WPAD_dpd_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_DPD(p_wpd) > 0) {
+ DIFF_COUNT_DPD(p_wpd)--;
+ }
+ }
+ }
+ }
+ result |= IsButtonChanged(curr->clButton, prev->clButton);
+ result |= IsAnalogChanged((s32)(curr->clLStickX / lstk), (s32)(prev->clLStickX / lstk), 1);
+ result |= IsAnalogChanged((s32)(curr->clLStickY / lstk), (s32)(prev->clLStickY / lstk), 1);
+ result |= IsAnalogChanged((s32)(curr->clRStickX / rstk), (s32)(prev->clRStickX / rstk), 1);
+ result |= IsAnalogChanged((s32)(curr->clRStickY / rstk), (s32)(prev->clRStickY / rstk), 1);
+ result |= IsAnalogChanged((s32)(curr->clTriggerL / trig), (s32)(prev->clTriggerL / trig), 1);
+ result |= IsAnalogChanged((s32)(curr->clTriggerR / trig), (s32)(prev->clTriggerR / trig), 1);
+ }
+ } else {
+ WPADStatusEx* curr = (WPADStatusEx*)p_curr;
+ WPADStatusEx* prev = (WPADStatusEx*)p_prev;
+
+ result |= IsButtonChanged(curr->base.button, prev->base.button);
+ if (curr->base.err == WPAD_ERR_OK && prev->base.err == WPAD_ERR_OK) {
+ if (IsAnalogChanged((s32)(curr->base.accX), (s32)(prev->base.accX), 12) |
+ IsAnalogChanged((s32)(curr->base.accY), (s32)(prev->base.accY), 12) |
+ IsAnalogChanged((s32)(curr->base.accZ), (s32)(prev->base.accZ), 12)) {
+ DIFF_COUNT_ACC(p_wpd)++;
+ if (DIFF_COUNT_ACC(p_wpd) > __WPAD_acc_diff_count_threshold) {
+ DIFF_COUNT_ACC(p_wpd) = 0;
+ HYST_COUNT_ACC(p_wpd) = 0;
+ result |= 1;
+ }
+
+ } else {
+ HYST_COUNT_ACC(p_wpd) = (u16)((HYST_COUNT_ACC(p_wpd) + 1) % __WPAD_acc_hyst_count_threshold);
+ if (HYST_COUNT_ACC(p_wpd) == __WPAD_acc_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_ACC(p_wpd) > 0) {
+ DIFF_COUNT_ACC(p_wpd)--;
+ }
+ }
+ }
+
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; i++) {
+ if (IsAnalogChanged((s32)(curr->base.obj[i].x), (s32)(prev->base.obj[i].x), 2) |
+ IsAnalogChanged((s32)(curr->base.obj[i].y), (s32)(prev->base.obj[i].y), 2)) {
+ DIFF_COUNT_DPD(p_wpd)++;
+ if (DIFF_COUNT_DPD(p_wpd) > __WPAD_dpd_diff_count_threshold) {
+ DIFF_COUNT_DPD(p_wpd) = 0;
+ result |= 1;
+ }
+ } else {
+ HYST_COUNT_DPD(p_wpd) = (u16)((HYST_COUNT_DPD(p_wpd) + 1) % __WPAD_dpd_hyst_count_threshold);
+ if (HYST_COUNT_DPD(p_wpd) == __WPAD_dpd_hyst_count_threshold - 1) {
+ if (DIFF_COUNT_DPD(p_wpd) > 0) {
+ DIFF_COUNT_DPD(p_wpd)--;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void WPADRecalibrate(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable = OSDisableInterrupts();
+ p_wpd->calibrated = 0;
+ OSRestoreInterrupts(enable);
+}
+
+inline void CheckButtonCombination(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ WPADCLStatus* status;
+ BOOL enable;
+ u8 index;
+ s8 cnt = 0;
+
+ enable = OSDisableInterrupts();
+ index = p_wpd->rxBufIndex == 0;
+ status = (WPADCLStatus*)(p_wpd->rxBufs + index);
+
+ if (status->base.button == 0x1C10) {
+ cnt = 1;
+ }
+
+ if (WPADiIsClFormat(p_wpd->dataFormat)) {
+ if (status->clButton == 0x1450) {
+ cnt = 1;
+ }
+ }
+
+ p_wpd->recalibrateCount = cnt != 0 ? p_wpd->recalibrateCount + 1 : 0;
+
+ OSRestoreInterrupts(enable);
+
+ if (p_wpd->recalibrateCount > 600) {
+ WPADRecalibrate(chan);
+ }
+}
+
+static void __SetScreenSaverFlag(BOOL flag) {
+ if (flag) {
+ VIResetRFIdle();
+ }
+}
+
+void WPADiCheckContInputs(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL diff = FALSE;
+ BOOL enable;
+ BOOL screen = FALSE;
+ void* p_data;
+ u8 index;
+
+ if (p_wpd->status == WPAD_ERR_NO_CONTROLLER) {
+ return;
+ }
+
+ enable = OSDisableInterrupts();
+ index = (u8)((p_wpd->rxBufIndex) ? 0 : 1);
+ p_data = (void*)(p_wpd->rxBufs + index);
+ diff = IsControllerDataChanged(p_wpd, p_data, p_wpd->prBuf);
+
+ if (diff) {
+ memcpy(p_wpd->prBuf, p_data, WPAD_RX_DATASIZE);
+ }
+ if (((WPADStatus*)p_wpd->prBuf)->err != WPAD_ERR_OK) {
+ memset(p_wpd->prBuf, 0, WPAD_RX_DATASIZE);
+ }
+
+ OSRestoreInterrupts(enable);
+ CheckButtonCombination(chan);
+
+ if (diff) {
+ screen = TRUE;
+ p_wpd->lastUpdateTime = __OSGetSystemTime();
+ } else {
+ if (_sleepTime > 0) {
+ int sec = (int)OSTicksToSeconds(__OSGetSystemTime() - p_wpd->lastUpdateTime);
+
+ if (sec > 60 * _sleepTime) {
+ WPADiDisconnect(chan, TRUE);
+ }
+ }
+ }
+
+ __SetScreenSaverFlag(screen);
+}
+
+s8 __wpadGetQueueSize(WPADCmdQueue* queue) {
+ BOOL enable;
+ s8 num;
+
+ enable = OSDisableInterrupts();
+
+ num = (s8)(queue->tail - queue->head);
+ if (num < 0) {
+ num += queue->cmdlen;
+ }
+
+ OSRestoreInterrupts(enable);
+ return num;
+}
+
+BOOL WPADiIsAvailableCmdQueue(WPADCmdQueue* queue, s8 cmd_num) {
+ s8 curr = __wpadGetQueueSize(queue);
+
+ if (curr + cmd_num <= queue->cmdlen - 1) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void WPADiClearQueue(WPADCmdQueue* queue) {
+ BOOL enable;
+
+ enable = OSDisableInterrupts();
+
+ queue->head = 0;
+ queue->tail = 0;
+ memset(queue->cmd, 0, queue->cmdlen * sizeof(WPADCommand));
+
+ OSRestoreInterrupts(enable);
+}
+
+BOOL __wpadPushCommand(WPADCmdQueue* queue, WPADCommand cmd) {
+ BOOL enable;
+
+ enable = OSDisableInterrupts();
+
+ if (__wpadGetQueueSize(queue) == queue->cmdlen - 1) {
+ OSRestoreInterrupts(enable);
+ return FALSE;
+ }
+
+ memset(queue->cmd + queue->tail, 0, sizeof(WPADCommand));
+ memcpy(queue->cmd + queue->tail, &cmd, sizeof(WPADCommand));
+ queue->tail = (s8)((queue->tail == queue->cmdlen - 1) ? 0 : queue->tail + 1);
+ OSRestoreInterrupts(enable);
+ return TRUE;
+}
+
+BOOL WPADiSendDPDCSB(WPADCmdQueue* queue, BOOL enable, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+
+ cmd.command = WPAD_HIDREP_DPDCSB;
+ cmd.len = 1;
+ cmd.data[0] = enable ? 4 : 0;
+ cmd.callback = callback;
+
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
+BOOL WPADiSendReadData(WPADCmdQueue* queue, void* p_buf, u16 len, u32 addr, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+
+ ASSERT(p_buf != NULL);
+
+ cmd.command = WPAD_HIDREP_RDDATA;
+ cmd.len = 6;
+ cmd.callback = callback;
+
+ memcpy(cmd.data, &addr, sizeof(addr));
+ memcpy(cmd.data + 4, &len, sizeof(len));
+
+ cmd.readBuf = p_buf;
+ cmd.readLen = len;
+ cmd.readAddr = addr;
+
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
+u16 __wpadGetBTEBufferStatus(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ s32 status;
+ s8 handle;
+
+ enable = OSDisableInterrupts();
+ status = p_wpd->status;
+ handle = p_wpd->devHandle;
+ OSRestoreInterrupts(enable);
+
+ if (status == WPAD_ERR_NO_CONTROLLER) {
+ return 0;
+ } else {
+ return _WUDGetQueuedSize(handle);
+ }
+}
+
+u16 __wpadGetBTMBufferStatus(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ s32 status;
+ s8 handle;
+
+ enable = OSDisableInterrupts();
+ status = p_wpd->status;
+ handle = p_wpd->devHandle;
+ OSRestoreInterrupts(enable);
+
+ if (status == WPAD_ERR_NO_CONTROLLER) {
+ return 0;
+ } else {
+ return _WUDGetNotAckedSize(handle);
+ }
+}
+
+void WPADiGetScSettings() {
+ if (_scSetting) {
+ if (SCCheckStatus() == 0) {
+ _dpdSensitivity = __GetDpdSensitivity();
+ _sensorBarPos = __GetSensorBarPosition();
+ _rumble = __GetMotorMode();
+ _speakerVolume = __GetSpeakerVolume();
+ _scSetting = 0;
+ }
+ }
+}
+
+void WPADiAfh() {
+ BOOL enable;
+ u8* channel = (u8*)OSPhysicalToCached(0x31A2);
+
+ DCInvalidateRange(channel, 1);
+ DEBUGPrint("WiFi uses channel = %d\n", *channel);
+
+ if (_afhChannel != *channel) {
+ enable = OSDisableInterrupts();
+ _afhChannel = (s8)*channel;
+ OSRestoreInterrupts(enable);
+ WUDSetDisableChannel(_afhChannel);
+ }
+}
+
+void WPADiContMapTableUpdate() {
+ if (_scFlush) {
+ if (SCCheckStatus() == 0) {
+ if (TRUE == SCSetBtDeviceInfoArray(&_scArray)) {
+ SCFlushAsync(NULL);
+ _scFlush = 0;
+ }
+ }
+ }
+}
+
+BOOL WPADiProcessExtCommand(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ WPADCommand cmd;
+ s32 err;
+
+ if (p_wpd->used && p_wpd->info.attach) {
+ if (WPADiGetCommand(&p_wpd->extCmdQueue, &cmd)) {
+ err = WPADiSendData(chan, cmd);
+ if (err == WPAD_ERR_OK) {
+ WPADiPopCommand(&p_wpd->extCmdQueue);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+#if SDK_AUG2010
+BOOL WPADiSendGetContStat(WPADCmdQueue* queue, WPADInfo* info, WPADCallback callback) {
+#else
+BOOL WPADiSendGetContStat(WPADCmdQueue* queue, WPADInfo* info, u32 addr, WPADCallback callback) {
+#endif
+ WPADCommand cmd;
+ BOOL result;
+
+ cmd.command = WPAD_HIDREP_GETSTAT;
+ cmd.len = 1;
+ cmd.data[0] = 0;
+ cmd.callback = callback;
+ cmd.info = info;
+
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
+BOOL WPADiSendWriteDataCmd(WPADCmdQueue* queue, u8 cmd, u32 addr, WPADCallback callback) {
+ return WPADiSendWriteData(queue, &cmd, 1, addr, callback);
+}
+
+BOOL WPADiSendWriteData(WPADCmdQueue* queue, void* p_buf, u16 len, u32 addr, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+ u8 length = (u8)(len & WPAD_WRITE_LEN_MASK);
+ ASSERTLINE(5830, len > 0 && len <= 16);
+ ASSERTLINE(5831, p_buf != NULL);
+ cmd.command = WPAD_HIDREP_WRDATA;
+ cmd.len = 21;
+ cmd.callback = callback;
+ memcpy(cmd.data, &addr, sizeof(addr));
+ memcpy(cmd.data + 4, &length, sizeof(length));
+ memcpy(cmd.data + 5, p_buf, len);
+
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
+BOOL WPADiSendSetPort(WPADCmdQueue* queue, u8 pattern, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+
+ cmd.command = WPAD_HIDREP_PORT;
+ cmd.len = 1;
+ cmd.data[0] = (u8)(pattern << 4);
+ cmd.callback = callback;
+
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
+static void setupCallback(s32 chan, s32 result) {
+ u16 size;
+ u32 addr;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ if (result == WPAD_ERR_NO_CONTROLLER) {
+ return;
+ }
+
+ if (result == WPAD_ESUCCESS) {
+ p_wpd->handshakeFinished = TRUE;
+
+ if (p_wpd->connectCallback) {
+ p_wpd->connectCallback(chan, result);
+ }
+ } else {
+ size = p_wpd->oldFw != 0 ? 20 : 42;
+ addr = p_wpd->oldFw != 0 ? WM_ADDR_MEM_176C : 0;
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, size, addr, setupCallback);
+ }
+}
+
+static void gameInfoCallback(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ if (result != WPAD_ETRANSFER) {
+ return;
+ }
+
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, sizeof(WPADMEMGameInfo), 0x2A, gameInfoCallback);
+}
+
+static void gameInfoCallback2(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ if (result != WPAD_ETRANSFER) {
+ return;
+ }
+
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, sizeof(WPADMEMGameInfo), 0x62, gameInfoCallback2);
+}
+
+static void firmwareCheckCallback(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u16 size;
+ u32 addr;
+ u8 port;
+ BOOL enable;
+
+ if (result == WPAD_ERR_NO_CONTROLLER) {
+ return;
+ }
+
+ enable = OSDisableInterrupts();
+ p_wpd->oldFw = (result == WPAD_ERR_OK) ? TRUE : FALSE;
+ p_wpd->status = WPAD_ERR_OK;
+ OSRestoreInterrupts(enable);
+ size = (u16)((result == WPAD_ERR_OK) ? 20 : 42);
+ addr = (u32)((result == WPAD_ERR_OK) ? WM_ADDR_MEM_176C : 0);
+
+ DEBUGPrint(" ==>this error means that the firmware is for NDEV %s\n",
+ p_wpd->oldFw != 0 ? "2.0" : "2.1 or later");
+ WPADiSendSetReportType(&p_wpd->stdCmdQueue, WPAD_FMT_CORE_BTN, NULL);
+ WPADiSendDPDCSB(&p_wpd->stdCmdQueue, FALSE, NULL);
+ WPADiSendSetPort(&p_wpd->stdCmdQueue, 0x01 << chan, NULL);
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, sizeof(WPADMEMGameInfo),
+ WM_ADDR_MEM_GAME_INFO_0, gameInfoCallback);
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, sizeof(WPADMEMGameInfo),
+ WM_ADDR_MEM_GAME_INFO_0 + sizeof(WPADMEMGameInfo), gameInfoCallback2);
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, size, addr, setupCallback);
+#if SDK_AUG2010
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, NULL);
+#else
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, 0, NULL);
+#endif
+}
+
+s32 WPADiRetrieveChannel(u8 dev_handle) {
+ u8* devAddr;
+ s32 i;
+
+ devAddr = _WUDGetDevAddr(dev_handle);
+
+ for (i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
+ if (!memcmp(_scArray.info[i + 10].bd_addr, devAddr, 6)) {
+ if (_chan_active_state[i] == 0) {
+ _chan_active_state[i] = 1;
+ return i;
+ }
+ }
+ }
+ for (i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
+ if (_chan_active_state[i] == 0) {
+ _chan_active_state[i] = 1;
+ memcpy(_scArray.info[i + 10].bd_addr, devAddr, 6);
+ _scFlush = 1;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void WPADiConnCallback(u8 dev_handle, u8 open) {
+ s32 chan = -1;
+ WPADControlBlock* p_wpd;
+ BOOL isCmdExist;
+ WPADCommand cmd;
+
+ if (open) {
+ DEBUGPrint("connection is opened\n");
+ chan = WPADiRetrieveChannel(dev_handle);
+ p_wpd = _wpdcb[chan];
+ _dev_handle_index[dev_handle] = (s8)(chan & 0xff);
+ __ClearControlBlock(chan);
+
+ p_wpd->devHandle = (s8)dev_handle;
+ p_wpd->devType = WPAD_DEV_CORE;
+ p_wpd->dataFormat = WPAD_FMT_CORE_BTN;
+ p_wpd->used = TRUE;
+ p_wpd->status = WPAD_ERR_OK;
+ p_wpd->radioSensitivity = 100;
+ p_wpd->disconnect = 0;
+ WPADiSendReadData(&p_wpd->stdCmdQueue, p_wpd->wmReadDataBuf, 1, WM_ADDR_MEM_1770, firmwareCheckCallback);
+ __SetScreenSaverFlag(TRUE);
+ } else {
+ DEBUGPrint("connection is closed\n");
+ chan = _dev_handle_index[dev_handle];
+ _dev_handle_index[dev_handle] = -1;
+
+ if (chan != -1) {
+ p_wpd = _wpdcb[chan];
+ p_wpd->status = WPAD_ERR_NO_CONTROLLER;
+
+ if (p_wpd->cmdBlkCallback) {
+ p_wpd->cmdBlkCallback(chan, WPAD_ERR_NO_CONTROLLER);
+ } else if (_wmb[chan].callback) {
+ _wmb[chan].callback(chan, WPAD_ERR_NO_CONTROLLER);
+ }
+ do {
+ isCmdExist = WPADiGetCommand(&p_wpd->stdCmdQueue, &cmd);
+ if (isCmdExist) {
+ if (cmd.callback) {
+ cmd.callback(chan, WPAD_ERR_NO_CONTROLLER);
+ }
+ WPADiPopCommand(&p_wpd->stdCmdQueue);
+ }
+ } while (isCmdExist);
+ DEBUGPrint("clean up command queue\n");
+
+ if (p_wpd->samplingBufs_ptr) {
+ WPADSetAutoSamplingBuf(chan, p_wpd->samplingBufs_ptr, p_wpd->samplingBufLength);
+ }
+
+ __ClearControlBlock(chan);
+ _chan_active_state[chan] = 0;
+
+ if (p_wpd->connectCallback) {
+ p_wpd->connectCallback(chan, WPAD_ERR_NO_CONTROLLER);
+ }
+ } else {
+ DEBUGPrint("WARNING: disconnection for device handle not assigned to channel.\n");
+ }
+ }
+}
+
+void WPADiRecvCallback(u8 dev_handle, u8* p_rpt, u16) {
+ u8 chan;
+ s32 err;
+
+ chan = (u8)_dev_handle_index[dev_handle];
+
+ if ((chan >= 0) && (chan <= WPAD_MAX_CONTROLLERS)) {
+ err = WPADiHIDParser(chan, p_rpt);
+ if (err) {
+ DEBUGPrint("HID Parser reports: %d\n", err);
+ }
+ } else {
+ DEBUGPrint("WPADiRecvCallback(): Unknown channel %d\n", chan);
+ }
+}
+
+void WPADGetAccGravityUnit(s32 chan, u32 type, WPADAcc* acc) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+
+ enable = OSDisableInterrupts();
+ if (acc) {
+ switch (type) {
+ case WPAD_DEV_CORE:
+ acc->x = (s16)(p_wpd->devConf.acc_1g.x - p_wpd->devConf.acc_0g.x);
+ acc->y = (s16)(p_wpd->devConf.acc_1g.y - p_wpd->devConf.acc_0g.y);
+ acc->z = (s16)(p_wpd->devConf.acc_1g.z - p_wpd->devConf.acc_0g.z);
+ break;
+
+ case WPAD_DEV_FS:
+ acc->x = (s16)(p_wpd->extConf.fs.acc_1g.x - p_wpd->extConf.fs.acc_0g.x);
+ acc->y = (s16)(p_wpd->extConf.fs.acc_1g.y - p_wpd->extConf.fs.acc_0g.y);
+ acc->z = (s16)(p_wpd->extConf.fs.acc_1g.z - p_wpd->extConf.fs.acc_0g.z);
+ break;
+ }
+ }
+ OSRestoreInterrupts(enable);
+}
+
+BOOL WPADiGetCommand(WPADCmdQueue* queue, WPADCommand* cmd) {
+ BOOL enable = OSDisableInterrupts();
+
+ if (__wpadGetQueueSize(queue) == 0) {
+ OSRestoreInterrupts(enable);
+ return FALSE;
+ }
+
+ memcpy(cmd, queue->cmd + queue->head, sizeof(WPADCommand));
+
+ OSRestoreInterrupts(enable);
+ return TRUE;
+}
+
+BOOL WPADiPopCommand(WPADCmdQueue* queue) {
+ BOOL enable = OSDisableInterrupts();
+
+ if (__wpadGetQueueSize(queue) == 0) {
+ OSRestoreInterrupts(enable);
+ return FALSE;
+ }
+
+ memset(queue->cmd + queue->head, 0, sizeof(WPADCommand));
+ queue->head = (s8)((queue->head == queue->cmdlen - 1) ? 0 : queue->head + 1);
+
+ OSRestoreInterrupts(enable);
+ return TRUE;
+}
+
+BOOL WPADiProcessCommand(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ WPADCommand cmd;
+ s32 err;
+
+ if (p_wpd->used) {
+ if (WPADiGetCommand(&p_wpd->stdCmdQueue, &cmd)) {
+ err = WPADiSendData(chan, cmd);
+ if (err == WPAD_ERR_OK) {
+ WPADiPopCommand(&p_wpd->stdCmdQueue);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static void __ClearControlBlock(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ p_wpd->rxBufIndex = 0;
+
+ p_wpd->infoOut = NULL;
+ p_wpd->motorRunning = FALSE;
+
+ p_wpd->cmdBlkCallback = NULL;
+ p_wpd->extensionCallback = NULL;
+ p_wpd->samplingCallback = NULL;
+ p_wpd->samplingBufs_ptr = NULL;
+ p_wpd->samplingBufIndex = 0;
+ p_wpd->samplingBufLength = 0;
+ p_wpd->dataFormat = WPAD_FMT_CORE_BTN;
+ p_wpd->status = WPAD_ERR_NO_CONTROLLER;
+ p_wpd->devType = WPAD_DEV_NONE;
+ p_wpd->devMode = 0;
+ p_wpd->calibrated = 0;
+ p_wpd->recalibrateCount = 0;
+ p_wpd->statusReqBusy = 0;
+ p_wpd->dpdDummyObjSize = 12;
+
+ DIFF_COUNT_DPD(p_wpd) = 0;
+ HYST_COUNT_DPD(p_wpd) = 0;
+ DIFF_COUNT_ACC(p_wpd) = 0;
+ HYST_COUNT_ACC(p_wpd) = 0;
+ DIFF_COUNT_FS_ACC(p_wpd) = 0;
+ HYST_COUNT_FS_ACC(p_wpd) = 0;
+
+ p_wpd->lastUpdateTime = __OSGetSystemTime();
+ p_wpd->lastReportSendTime = __OSGetSystemTime();
+ p_wpd->cmdTimeoutAction = 0;
+#if SDK_SEP2006
+ p_wpd->reqVolume = 0;
+ p_wpd->reqVolCb = NULL;
+#endif
+
+ p_wpd->wmReadDataPtr = NULL;
+ p_wpd->wmReadAddr = 0;
+ p_wpd->wmReadLength = 0;
+ p_wpd->wmReadErr = 0;
+
+ p_wpd->devHandle = -1;
+ p_wpd->used = FALSE;
+ p_wpd->handshakeFinished = FALSE;
+ p_wpd->oldFw = FALSE;
+ p_wpd->radioQuality = 1;
+ p_wpd->radioQualityOkMs = 0;
+ p_wpd->audioFrames = 0;
+
+ p_wpd->keyIdx = 0;
+ p_wpd->radioSensitivity = 0;
+ p_wpd->packetCnt = 0;
+ p_wpd->disconnect = 1;
+
+ memset(&p_wpd->info, 0, sizeof(WPADInfo));
+ memset(p_wpd->wmReadDataBuf, 0, sizeof(p_wpd->wmReadDataBuf));
+ memset(p_wpd->rxBufs, 0, WPAD_RX_DATASIZE * 2);
+ memset(p_wpd->prBuf, 0, WPAD_RX_DATASIZE);
+ memset(&p_wpd->devConf, 0, sizeof(WPADDevConfig));
+ memset(&p_wpd->extConf, 0, sizeof(WPADExtConfig));
+ memset(&p_wpd->key, 0, sizeof(p_wpd->key));
+ memset(&p_wpd->ft, 0, sizeof(p_wpd->ft));
+ memset(&p_wpd->sb, 0, sizeof(p_wpd->sb));
+ memset(&p_wpd->gameInfo, 0, sizeof(WPADMEMGameInfo));
+
+ p_wpd->gameInfoErr[0] = WPAD_ERR_NO_CONTROLLER;
+ p_wpd->gameInfoErr[1] = WPAD_ERR_NO_CONTROLLER;
+ p_wpd->stdCmdQueue.cmd = p_wpd->stdCmdQueueList;
+ p_wpd->stdCmdQueue.cmdlen = ARRAY_SIZE(p_wpd->stdCmdQueueList);
+ p_wpd->extCmdQueue.cmd = p_wpd->extCmdQueueList;
+ p_wpd->extCmdQueue.cmdlen = ARRAY_SIZE(p_wpd->extCmdQueueList);
+ WPADiClearQueue(&p_wpd->stdCmdQueue);
+ WPADiClearQueue(&p_wpd->extCmdQueue);
+
+ _wmb[chan].used = FALSE;
+ _wmb[chan].p_buf = NULL;
+ _wmb[chan].len = 0;
+ _wmb[chan].addr = 0;
+ _wmb[chan].callback = NULL;
+}
+
+BOOL WPADStartSimpleSync() {
+ WUDStartSyncSimple();
+}
+
+BOOL WPADStartFastSimpleSync() {
+ return WUDStartFastSyncSimple();
+}
+
+BOOL WPADStopSimpleSync() {
+ return WUDStopSyncSimple();
+}
+
+WPADSyncDeviceCallback WPADSetSimpleSyncCallback(WPADSyncDeviceCallback callback) {
+ return WUDSetSyncSimpleCallback(callback);
+}
+
+void WPADRegisterAllocator(WPADAlloc alloc, WPADFree free) {
+ WUDRegisterAllocator(alloc, free);
+}
+
+u32 WPADGetWorkMemorySize(void) {
+ return WUDGetAllocatedMemSize();
+}
+
+s32 WPADGetStatus() {
+ return WUDGetStatus();
+}
+
+u8 WPADGetSensorBarPosition() {
+ BOOL enable;
+ u8 pos;
+
+ enable = OSDisableInterrupts();
+ pos = _sensorBarPos;
+ OSRestoreInterrupts(enable);
+ return pos;
+}
+
+void WPADDisconnect(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ memset(&_scArray.info[chan + 10], 0, sizeof(SCBtDeviceInfoSingle));
+ _scFlush = 1;
+ WPADiDisconnect(chan, TRUE);
+}
+
+void WPADSetAutoSleepTime(u8 minute) {
+ BOOL enable = OSDisableInterrupts();
+ _sleepTime = minute;
+ OSRestoreInterrupts(enable);
+}
+
+s32 WPADProbe(s32 chan, u32* devType) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ s32 status;
+ BOOL enable = OSDisableInterrupts();
+ if (devType != NULL) {
+ *devType = p_wpd->devType;
+ }
+ status = p_wpd->status;
+ if (status != WPAD_ERR_NO_CONTROLLER) {
+ if (p_wpd->devType == WPAD_DEV_NONE) {
+ status = WPAD_ERR_NO_CONTROLLER;
+ } else if (!p_wpd->handshakeFinished) {
+ status = WPAD_ERR_BUSY;
+ }
+ }
+ OSRestoreInterrupts(enable);
+ return status;
+}
+
+WPADSamplingCallback WPADSetSamplingCallback(s32 chan, WPADSamplingCallback cb) {
+ WPADControlBlock* p_wpd;
+ WPADSamplingCallback prev;
+ BOOL enable;
+
+ DEBUGPrint("WPADSetSamplingCallback()\n");
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ prev = p_wpd->samplingCallback;
+ p_wpd->samplingCallback = cb;
+ OSRestoreInterrupts(enable);
+ return prev;
+}
+
+WPADConnectCallback WPADSetConnectCallback(s32 chan, WPADConnectCallback cb) {
+ WPADControlBlock* p_wpd;
+ WPADConnectCallback prev;
+ BOOL enable;
+
+ DEBUGPrint("WPADSetConnectCallback()\n");
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ prev = p_wpd->connectCallback;
+ p_wpd->connectCallback = cb;
+ OSRestoreInterrupts(enable);
+ return prev;
+}
+
+WPADExtensionCallback WPADSetExtensionCallback(s32 chan, WPADExtensionCallback cb) {
+ WPADControlBlock* p_wpd;
+ WPADExtensionCallback prev;
+ BOOL enable;
+
+ DEBUGPrint("WPADSetExtensionCallback()\n");
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ prev = p_wpd->extensionCallback;
+ p_wpd->extensionCallback = cb;
+ OSRestoreInterrupts(enable);
+
+ return prev;
+}
+
+void WPADSetAutoSamplingBuf(s32 chan, void* buf, u32 cnt) {
+ WPADControlBlock* p_wpd;
+ BOOL enabled;
+ s8 err;
+ size_t step;
+ s32 i;
+ size_t off;
+ WPADStatus* status;
+ WPADStatus* base;
+
+ DEBUGPrint("WPADSetAutoSamplingBuf()\n");
+ enabled = OSDisableInterrupts();
+
+ p_wpd = _wpdcb[chan];
+ err = p_wpd->status == WPAD_ERR_NO_CONTROLLER ? WPAD_ERR_NO_CONTROLLER : WPAD_ERR_INVALID;
+
+ if (WPADiIsCoreFormat(p_wpd->dataFormat)) {
+ step = sizeof(WPADStatus);
+ } else if (WPADiIsFsFormat(p_wpd->dataFormat)) {
+ step = sizeof(WPADFSStatus);
+ } else if (WPADiIsClFormat(p_wpd->dataFormat)) {
+ step = sizeof(WPADCLStatus);
+ } else {
+ step = 0x5A;
+ }
+
+ if (buf != NULL) {
+ memset(buf, 0, step * cnt);
+
+ off = 0;
+ for (i = 0; i < cnt; i++) {
+ status = (WPADStatus*)((uintptr_t)buf + off);
+ off += step;
+ status->err = err;
+ }
+
+ p_wpd->samplingBufIndex = -1;
+ p_wpd->samplingBufLength = cnt;
+ }
+
+ p_wpd->samplingBufs_ptr = buf;
+
+ OSRestoreInterrupts(enabled);
+}
+
+u32 WPADGetLatestIndexInBuf(s32 chan, void* buf) {
+ BOOL enable;
+ u32 idx;
+
+ enable = OSDisableInterrupts();
+ idx = _wpdcb[chan]->samplingBufIndex;
+ OSRestoreInterrupts(enable);
+
+ return idx == -1 ? 0 : idx;
+}
+
+void WPADiExcludeButton(s32 chan) {
+ WPADControlBlock *cb = _wpdcb[chan];
+ BOOL irq = OSDisableInterrupts();
+
+ WPADStatus* status = (WPADStatus*)&cb->rxBufs[(u8)(cb->rxBufIndex == 0)];
+
+ if ((status->button & 0x0003) == 0x0003) {
+ status->button &= ~0x0002;
+ }
+
+ if ((status->button & 0x000C) == 0x000C) {
+ status->button &= ~0x0004;
+ }
+
+ if (cb->dataFormat == WPAD_FMT_CLASSIC_BTN ||
+ cb->dataFormat == WPAD_FMT_CLASSIC_BTN_ACC ||
+ cb->dataFormat == WPAD_FMT_CLASSIC_BTN_ACC_DPD) {
+ WPADCLStatus* cl = (WPADCLStatus*)status;
+ if ((cl->clButton & 0x8002) == 0x8002) {
+ cl->clButton &= ~0x8000;
+ }
+
+ if ((cl->clButton & 0x4001) == 0x4001) {
+ cl->clButton &= ~0x4000;
+ }
+ }
+
+ OSRestoreInterrupts(irq);
+}
+
+static void __SendData(s32 chan, WPADCommand cmd) {
+ BOOL enable;
+ BOOL motor;
+ BT_HDR* p_buf = NULL;
+ u8* ptr;
+ s8 handle;
+ s32 status;
+ WPADControlBlock* p_wpd;
+ u8 rep_id = (u8)cmd.command;
+ u8* p_data = cmd.data;
+ u16 len = cmd.len;
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ status = p_wpd->status;
+ handle = p_wpd->devHandle;
+ if (handle < 0) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+ p_wpd->status = WPAD_ERR_BUSY;
+ motor = p_wpd->motorRunning & _rumble;
+ OSRestoreInterrupts(enable);
+
+ if (rep_id == WPAD_HIDREP_VIBRATOR) {
+ enable = OSDisableInterrupts();
+ p_wpd->status = status;
+ OSRestoreInterrupts(enable);
+ } else if (rep_id == WPAD_HIDREP_STRM) {
+ enable = OSDisableInterrupts();
+ p_wpd->status = status;
+ p_wpd->audioFrames--;
+ OSRestoreInterrupts(enable);
+ } else {
+ enable = OSDisableInterrupts();
+ switch (rep_id) {
+ case WPAD_HIDREP_WRDATA:
+ break;
+
+ case WPAD_HIDREP_RDDATA:
+ p_wpd->wmReadErr = 0;
+ p_wpd->wmReadAddr = cmd.readAddr;
+ p_wpd->wmReadLength = cmd.readLen;
+ p_wpd->wmReadDataPtr = cmd.readBuf;
+ break;
+
+ case WPAD_HIDREP_GETSTAT:
+ p_wpd->status = status;
+ p_wpd->infoOut = cmd.info;
+ p_wpd->statusReqBusy = 1;
+ break;
+
+ case WPAD_HIDREP_WAIT: {
+ OSTick tick;
+ memcpy(&tick, cmd.data, sizeof(OSTick));
+ p_wpd->lastReportSendTime = tick + __OSGetSystemTime();
+ p_wpd->cmdTimeoutAction = 1;
+ return;
+ }
+
+ default:
+ p_data[0] |= 0x2;
+ break;
+ }
+
+ p_wpd->cmdBlkCallback = cmd.callback;
+ p_wpd->lastReportId = rep_id;
+ p_wpd->lastReportSendTime = OSSecondsToTicks(_sleepTime * 60) + __OSGetSystemTime();
+ p_wpd->cmdTimeoutAction = 0;
+ OSRestoreInterrupts(enable);
+ }
+
+ DEBUGPrint("handle = %d, repid = %02x\n", handle, rep_id);
+
+ p_buf = GKI_getbuf((u8)(10 + len + sizeof(BT_HDR)));
+ p_buf->len = (u8)(len + 1);
+ p_buf->offset = 10;
+ ptr = (u8*)(p_buf + 1) + p_buf->offset;
+
+ ptr[0] = rep_id;
+
+ memcpy(ptr + 1, p_data, len);
+
+ if (motor) {
+ ptr[1] |= 1;
+ } else {
+ ptr[1] &= ~1;
+ }
+
+ BTA_HhSendData((u8)handle, p_buf);
+}
+
+s32 WPADiSendData(s32 chan, WPADCommand cmd) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ s32 status;
+ BOOL enable;
+ BOOL getStat;
+ int t;
+
+ status = WPADiGetStatus(chan);
+
+ if (status == WPAD_ERR_OK) {
+ enable = OSDisableInterrupts();
+ getStat = p_wpd->statusReqBusy;
+ OSRestoreInterrupts(enable);
+
+ if (getStat) {
+ status = WPAD_ERR_BUSY;
+ } else {
+ __SendData(chan, cmd);
+ }
+ } else if (status != WPAD_ERR_BUSY) {
+ if (status == WPAD_ERR_TRANSFER) {
+ enable = OSDisableInterrupts();
+ p_wpd->status = WPAD_ERR_OK;
+ OSRestoreInterrupts(enable);
+ }
+ } else {
+ t = (int)OSTicksToSeconds(__OSGetSystemTime() - p_wpd->lastReportSendTime);
+ if (t > 1 && _sleepTime > 0) {
+ if (p_wpd->cmdTimeoutAction == 0) {
+ p_wpd->lastReportSendTime = __OSGetSystemTime();
+ WPADiDisconnect(chan, TRUE);
+ } else {
+ enable = OSDisableInterrupts();
+ p_wpd->status = WPAD_ERR_TRANSFER;
+ OSRestoreInterrupts(enable);
+ }
+ }
+ }
+ return status;
+}
+
+void WPADiRumbleMotor(s32 chan, BOOL sendCmd) {
+ WPADCommand cmd;
+
+ if (_wpdcb[chan]->status == WPAD_ERR_NO_CONTROLLER) {
+ return;
+ }
+
+ if (sendCmd == TRUE || __wpadGetQueueSize(&_wpdcb[chan]->stdCmdQueue) > 0) {
+ _wpdcb[chan]->motorBusy = FALSE;
+ } else if (_rumbleCnt[chan] == 5) {
+ _wpdcb[chan]->motorBusy = FALSE;
+
+ cmd.command = WPAD_HIDREP_VIBRATOR;
+ cmd.len = 1;
+ cmd.data[0] = 0;
+ cmd.callback = NULL;
+
+ __SendData(chan, cmd);
+ }
+ _rumbleCnt[chan] = (u8)((_wpdcb[chan]->motorBusy) ? _rumbleCnt[chan] + 1 : 0);
+}
+
+u32 WPADGetDataFormat(s32 chan) {
+ WPADControlBlock* p_wpd;
+ u32 fmt;
+ BOOL enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ fmt = p_wpd->dataFormat;
+ OSRestoreInterrupts(enable);
+ return fmt;
+}
+
+s32 WPADSetDataFormat(s32 chan, u32 fmt) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ s32 ret;
+ BOOL busy;
+ BOOL enable;
+ BOOL setup;
+ u32 prevFmt;
+
+ enable = OSDisableInterrupts();
+ setup = p_wpd->handshakeFinished;
+ ret = p_wpd->status;
+ prevFmt = p_wpd->dataFormat;
+ OSRestoreInterrupts(enable);
+
+ if (ret != WPAD_ERR_NO_CONTROLLER) {
+ if (!setup) {
+ ret = WPAD_ERR_BUSY;
+ } else if (prevFmt != fmt) {
+ busy = WPADiSendSetReportType(&p_wpd->stdCmdQueue, fmt, NULL);
+ if (!busy) {
+ ret = WPAD_ERR_BUSY;
+ } else {
+ enable = OSDisableInterrupts();
+ p_wpd->dataFormat = fmt;
+ OSRestoreInterrupts(enable);
+ ret = WPAD_ERR_OK;
+ }
+ } else {
+ ret = WPAD_ERR_OK;
+ }
+ }
+ return ret;
+}
+
+void WPADiDisconnect(s32 chan, BOOL polite) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ s32 status;
+
+ status = WPADiGetStatus(chan);
+
+ if (status != WPAD_ERR_NO_CONTROLLER) {
+ if (polite) {
+ enable = OSDisableInterrupts();
+ if (p_wpd->disconnect) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+ p_wpd->disconnect = 1;
+ OSRestoreInterrupts(enable);
+ BTA_HhClose(p_wpd->devHandle);
+ } else {
+ u8 addr[6];
+ WPADGetAddress(chan, addr);
+ btm_remove_acl(addr);
+ }
+ }
+}
+
+s32 WPADGetInfoAsync(s32 chan, WPADInfo* info, WPADCallback callback) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ BOOL setup;
+ s32 result;
+
+ enable = OSDisableInterrupts();
+ setup = p_wpd->handshakeFinished;
+ result = p_wpd->status;
+ OSRestoreInterrupts(enable);
+
+ if (result != WPAD_ERR_NO_CONTROLLER) {
+ if (!setup) {
+ result = WPAD_ERR_BUSY;
+ } else {
+#if SDK_AUG2010
+ if (WPADiSendGetContStat(&p_wpd->stdCmdQueue, info, callback)) {
+#else
+ if (WPADiSendGetContStat(&p_wpd->stdCmdQueue, info, 0, callback)) {
+#endif
+ result = WPAD_ERR_OK;
+ } else {
+ result = WPAD_ERR_BUSY;
+ }
+ }
+ }
+
+ return result;
+}
+
+void WPADControlMotor(s32 chan, u32 command) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ BOOL needed = FALSE;
+ s32 status;
+
+ enable = OSDisableInterrupts();
+ status = p_wpd->status;
+
+ if (status == WPAD_ERR_NO_CONTROLLER) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+
+ if (_rumble == FALSE) {
+ if (command != WPAD_MOTOR_STOP || p_wpd->motorRunning != TRUE) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+ }
+
+ if ((command == WPAD_MOTOR_STOP && p_wpd->motorRunning == FALSE) || (command == WPAD_MOTOR_RUMBLE && p_wpd->motorRunning == TRUE)) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+
+ p_wpd->motorRunning = (command == WPAD_MOTOR_STOP) ? FALSE : TRUE;
+ p_wpd->motorBusy = TRUE;
+ OSRestoreInterrupts(enable);
+}
+
+void WPADEnableMotor(BOOL enable) {
+ BOOL intr = OSDisableInterrupts();
+ _rumble = enable;
+ OSRestoreInterrupts(intr);
+}
+
+BOOL WPADIsMotorEnabled() {
+ BOOL result;
+ BOOL enable = OSDisableInterrupts();
+ result = _rumble;
+ OSRestoreInterrupts(enable);
+ return result;
+}
+
+s32 WPADControlLed(s32 chan, u8 pattern, WPADCallback callback) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL busy;
+ BOOL enable;
+ BOOL setup;
+ s32 result = WPAD_ERR_OK;
+
+ enable = OSDisableInterrupts();
+ result = p_wpd->status;
+ setup = p_wpd->handshakeFinished;
+ OSRestoreInterrupts(enable);
+
+ if (result != WPAD_ERR_NO_CONTROLLER) {
+ if (!setup) {
+ result = WPAD_ERR_BUSY;
+ } else {
+ busy = WPADiSendSetPort(&p_wpd->stdCmdQueue, pattern, callback);
+ result = (busy) ? WPAD_ERR_OK : WPAD_ERR_BUSY;
+ }
+ }
+
+ if (result != WPAD_ERR_OK) {
+ if (callback) {
+ callback(chan, result);
+ }
+ }
+ return result;
+}
+
+BOOL WPADSaveConfig(WPADFlushCallback callback) {
+ BOOL result = TRUE;
+ BOOL enable;
+ u8 volume;
+ u8 mode;
-wpad_cb_st* __rvl_p_wpadcb[WPAD_MAX_CONTROLLERS];
+ if (SCCheckStatus() != 0) {
+ return FALSE;
+ }
-static u8 _wpadSpeakerVol;
+ enable = OSDisableInterrupts();
+ volume = _speakerVolume;
+ mode = (u8)((_rumble) ? 1 : 0);
+ OSRestoreInterrupts(enable);
-static s8 __wpadGetQueueSize(struct WPADCmdQueue* cmdQueue);
-static u16 __wpadGetBTEBufferStatus(s32 chan);
-static u16 __wpadGetBTMBufferStatus(s32 chan);
-static BOOL __wpadPushCommand(struct WPADCmdQueue* cmdQueue, struct WPADCmd cmdBlk);
+ result &= SCSetWpadSpeakerVolume(volume);
+ result &= SCSetWpadMotorMode(mode);
-void dummyString(void* p_buf) {
- ASSERTLINE(0, p_buf != NULL);
+ if (result) {
+ SCFlushAsync(callback);
+ } else if (callback) {
+ callback(2);
+ }
+ return result;
}
-static u32 __wpadFmt2Size(u32 fmt) {
+#if SDK_AUG2010
+u32 __wpadFmt2Size(u32 fmt) {
u32 fmtSize;
switch (fmt) {
@@ -65,9 +1883,10 @@ static u32 __wpadFmt2Size(u32 fmt) {
return fmtSize;
}
+#endif
u8 WPADGetRadioSensitivity(s32 chan) {
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
+ WPADControlBlock* p_wpd = _wpdcb[chan];
BOOL intrStatus = OSDisableInterrupts();
u8 radioSensitivity = p_wpd->radioSensitivity;
@@ -75,8 +1894,28 @@ u8 WPADGetRadioSensitivity(s32 chan) {
return radioSensitivity;
}
+BOOL WPADSetAcceptConnection(u8 accept) {
+ BOOL result = FALSE;
+ BOOL visible = accept ? TRUE : FALSE;
+ if (WUDGetStatus() == 3) {
+ WUDSetVisibility(0, visible);
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL WPADGetAcceptConnection(void) {
+ if ((u8)WUDGetConnectable() == TRUE) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+#if SDK_AUG2010
void WPADRead(s32 chan, WPADStatus* status) {
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
+ WPADControlBlock* p_wpd = _wpdcb[chan];
BOOL intrStatus;
u8 rxBufIndex;
WPADStatus* rxStatus;
@@ -88,7 +1927,7 @@ void WPADRead(s32 chan, WPADStatus* status) {
intrStatus = OSDisableInterrupts();
rxBufIndex = p_wpd->rxBufIndex != 0 ? 0 : 1;
- rxStatus = (WPADStatus*)p_wpd->rxBufs[rxBufIndex];
+ rxStatus = (WPADStatus*)&p_wpd->rxBufs[rxBufIndex];
fmtSize = __wpadFmt2Size(p_wpd->dataFormat);
if (rxStatus->err != WPAD_ESUCCESS)
@@ -98,123 +1937,308 @@ void WPADRead(s32 chan, WPADStatus* status) {
OSRestoreInterrupts(intrStatus);
}
+#else
+void WPADRead(s32 chan, WPADStatus* status) {
+ WPADControlBlock* p_wpd;
+ BOOL intrStatus;
+ u8 step;
+ WPADUnkStatus* src;
-BOOL WPADIsSpeakerEnabled(s32 chan) {
- BOOL enabled;
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
- BOOL intrStatus = OSDisableInterrupts();
-
- enabled = p_wpd->info.speaker;
-
- OSRestoreInterrupts(intrStatus);
- return enabled;
-}
+ intrStatus = OSDisableInterrupts();
-s32 WPADControlSpeaker(s32 chan, u32 command, WPADCallback cb) {
- u8 data[7] = {0x00, 0x00, 0xd0, 0x07, 0x40, 0x0c, 0x0e};
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
- BOOL intrStatus = OSDisableInterrupts();
- BOOL speakerEnabled = p_wpd->info.speaker;
- BOOL handshakeFinished;
- s32 status = p_wpd->status;
+ p_wpd = _wpdcb[chan];
+ src = &p_wpd->rxBufs[(u8)(p_wpd->rxBufIndex == 0)];
+
+ if (p_wpd->status == WPAD_ERR_OK) {
+ if (WPADiIsCoreFormat(p_wpd->dataFormat))
+ {
+ memcpy(status, src, sizeof(WPADStatus));
+ } else if (WPADiIsFsFormat(p_wpd->dataFormat))
+ {
+ memcpy(status, src, sizeof(WPADFSStatus));
+ } else if (WPADiIsClFormat(p_wpd->dataFormat))
+ {
+ memcpy(status, src, sizeof(WPADCLStatus));
+ } else {
+ memcpy(status, src, 0x5A);
+ }
+ } else if (p_wpd->status == WPAD_ERR_BUSY) {
+ memcpy(status, src, sizeof(WPADStatus));
+ } else {
+ if (WPADiIsCoreFormat(p_wpd->dataFormat))
+ {
+ memset(status, 0, sizeof(WPADStatus));
+ } else if (WPADiIsFsFormat(p_wpd->dataFormat))
+ {
+ memset(status, 0, sizeof(WPADFSStatus));
+ } else if (WPADiIsClFormat(p_wpd->dataFormat))
+ {
+ memset(status, 0, sizeof(WPADCLStatus));
+ } else {
+ memset(status, 0, 0x5A);
+ }
- handshakeFinished = p_wpd->handshakeFinished;
+ status->err = p_wpd->status;
+ }
OSRestoreInterrupts(intrStatus);
+}
+#endif
+
+void WPADiCopyOut(s32 chan) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ WPADUnkStatus* p_data;
+ u8 index;
+ u32 size;
+
+ enable = OSDisableInterrupts();
+ p_data = &p_wpd->rxBufs[(u8)(p_wpd->rxBufIndex == 0)];
+
+ if (p_wpd->samplingBufs_ptr) {
+ p_wpd->samplingBufIndex++;
+ if (p_wpd->samplingBufIndex >= p_wpd->samplingBufLength) {
+ p_wpd->samplingBufIndex = 0;
+ }
- if (status == WPAD_ENODEV)
- goto end;
-
- if (!handshakeFinished) {
- status = WPAD_EBUSY;
- goto end;
+ if (WPADiIsCoreFormat(p_wpd->dataFormat)) {
+ WPADStatus* p_stat = (WPADStatus*)p_wpd->samplingBufs_ptr + p_wpd->samplingBufIndex;
+ size = sizeof(WPADStatus);
+ memcpy(p_stat, p_data, size);
+ } else if (WPADiIsFsFormat(p_wpd->dataFormat)) {
+ WPADFSStatus* p_stat = (WPADFSStatus*)p_wpd->samplingBufs_ptr + p_wpd->samplingBufIndex;
+ size = (p_data->base.err == WPAD_ERR_OK) ? sizeof(WPADFSStatus) : sizeof(WPADStatus);
+ memcpy(p_stat, p_data, size);
+ } else if (WPADiIsClFormat(p_wpd->dataFormat)) {
+ WPADCLStatus* p_stat = (WPADCLStatus*)p_wpd->samplingBufs_ptr + p_wpd->samplingBufIndex;
+ size = (p_data->base.err == WPAD_ERR_OK) ? sizeof(WPADCLStatus) : sizeof(WPADStatus);
+ memcpy(p_stat, p_data, size);
+ } else {
+ WPADStatusEx* p_stat = (WPADStatusEx*)p_wpd->samplingBufs_ptr + p_wpd->samplingBufIndex;
+ size = (p_data->base.err == WPAD_ERR_OK) ? sizeof(WPADStatusEx) : sizeof(WPADStatus);
+ memcpy(p_stat, p_data, size);
+ }
+ }
+ if (p_wpd->samplingCallback) {
+ p_wpd->samplingCallback(chan);
}
- if (command == WPAD_SPEAKER_DISABLE) {
- if (!speakerEnabled) {
- status = WPAD_ESUCCESS;
- goto end;
- }
+ p_wpd->packetCnt++;
+ OSRestoreInterrupts(enable);
+}
- intrStatus = OSDisableInterrupts();
+BOOL WPADIsSpeakerEnabled(s32 chan) {
+ BOOL state;
+ BOOL enable;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ enable = OSDisableInterrupts();
+ state = p_wpd->info.speaker;
+ OSRestoreInterrupts(enable);
+ return state;
+}
- if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 5)) {
- WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
- WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 0x01, WM_REG_SPEAKER_01, NULL);
- WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 0x00, WM_REG_SPEAKER_09, NULL);
- WPADiSendEnableSpeaker(&p_wpd->stdCmdQueue, FALSE, NULL);
- WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, cb);
+BOOL WPADiSendMuteSpeaker(WPADCmdQueue* queue, BOOL enable, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+ cmd.command = WPAD_HIDREP_MUTE;
+ cmd.len = 1;
+ cmd.data[0] = (u8)((enable) ? (u8)4 : (u8)0);
+ cmd.callback = callback;
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
- OSRestoreInterrupts(intrStatus);
+BOOL WPADiSendEnableSpeaker(WPADCmdQueue* queue, BOOL enable, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
+ cmd.command = WPAD_HIDREP_ENSPK;
+ cmd.len = 1;
+ cmd.data[0] = (u8)((enable) ? (u8)4 : (u8)0);
+ cmd.callback = callback;
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
- return WPAD_ESUCCESS;
+s32 WPADControlSpeaker(s32 chan, u32 command, WPADCallback callback) {
+ BOOL enable;
+ BOOL spk;
+ BOOL setup;
+ s32 result;
+ u8 initCmd[] = {0x00, 0x00, 0xd0, 0x07, 0x40, 0x0c, 0x0e};
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ enable = OSDisableInterrupts();
+ spk = p_wpd->info.speaker;
+ result = p_wpd->status;
+ setup = p_wpd->handshakeFinished;
+ OSRestoreInterrupts(enable);
+
+ if (result != WPAD_ERR_NO_CONTROLLER) {
+ if (!setup) {
+ result = WPAD_ERR_BUSY;
+ } else if (command == 0) {
+ if (!spk) {
+ result = WPAD_ERR_OK;
+ } else {
+ enable = OSDisableInterrupts();
+ if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 5)) {
+ WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, SPK_DERESET, SPK_RST_REG, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, SPK_CLK_OFF, SPK_CLK_REG, NULL);
+#if SDK_AUG2010
+ WPADiSendEnableSpeaker(&p_wpd->stdCmdQueue, FALSE, NULL);
+#else
+ WPADiSendEnableSpeaker(&p_wpd->stdCmdQueue, FALSE, callback);
+#endif
+#if SDK_AUG2010
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, callback);
+#else
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, 0, callback);
+#endif
+ OSRestoreInterrupts(enable);
+ return WPAD_ERR_OK;
+ } else {
+ result = WPAD_ERR_BUSY;
+ }
+ OSRestoreInterrupts(enable);
+ }
+ } else {
+ switch (command) {
+ case 1:
+#if SDK_AUG2010
+ case 5:
+#endif
+ enable = OSDisableInterrupts();
+ if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 7)) {
+ WPADiSendEnableSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
+ WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, SPK_CLK_ON, SPK_CLK_REG, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, SPK_RESET, SPK_RST_REG, NULL);
+ initCmd[4] = _speakerVolume;
+#if SDK_AUG2010
+ WPADiSendWriteData(&p_wpd->stdCmdQueue, initCmd, sizeof(initCmd), SPK_RST_REG, NULL);
+#else
+ WPADiSendWriteData(&p_wpd->stdCmdQueue, initCmd, sizeof(initCmd), SPK_RST_REG, callback);
+#endif
+ WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, FALSE, NULL);
+#if SDK_AUG2010
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, callback);
+#else
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, 0, NULL);
+#endif
+ OSRestoreInterrupts(enable);
+ return WPAD_ERR_OK;
+ } else {
+ result = WPAD_ERR_BUSY;
+ }
+ OSRestoreInterrupts(enable);
+ break;
+
+ case 2:
+ if (!WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, callback)) {
+ result = WPAD_ERR_BUSY;
+ } else {
+ return WPAD_ERR_OK;
+ }
+ break;
+
+ case 3:
+ if (!WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, FALSE, callback)) {
+ result = WPAD_ERR_BUSY;
+ } else {
+ return WPAD_ERR_OK;
+ }
+ break;
+
+ case 4:
+ if (!WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, SPK_CTRL_PLAY, SPK_CTRL_REG, callback)) {
+ result = WPAD_ERR_BUSY;
+ } else {
+ return WPAD_ERR_OK;
+ }
+ break;
+ }
}
+ }
- status = WPAD_EBUSY;
- OSRestoreInterrupts(intrStatus);
- } else {
- switch (command) {
- case WPAD_SPEAKER_ENABLE:
- case WPAD_SPEAKER_CMD_05:
- intrStatus = OSDisableInterrupts();
+ if (callback) {
+ callback(chan, result);
+ }
- if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 7)) {
- WPADiSendEnableSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
- WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, NULL);
- WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 0x01, WM_REG_SPEAKER_09, NULL);
+ return result;
+}
- // sends 0x80 instead of 0x08?
- WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 0x80, WM_REG_SPEAKER_01, NULL);
+u8 WPADGetSpeakerVolume() {
+ BOOL enable;
+ u8 vol;
- data[4] = _wpadSpeakerVol;
- WPADiSendWriteData(&p_wpd->stdCmdQueue, &data, sizeof data, WM_REG_SPEAKER_01,
- NULL);
- WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, FALSE, NULL);
- WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, cb);
+ enable = OSDisableInterrupts();
+ vol = _speakerVolume;
+ OSRestoreInterrupts(enable);
- OSRestoreInterrupts(intrStatus);
+ return vol;
+}
- return WPAD_ESUCCESS;
- }
+void WPADSetSpeakerVolume(u8 volume) {
+ BOOL enable;
- status = WPAD_EBUSY;
+ enable = OSDisableInterrupts();
+ _speakerVolume = volume;
+ OSRestoreInterrupts(enable);
+}
- OSRestoreInterrupts(intrStatus);
- break;
- case WPAD_SPEAKER_MUTE:
- if (!WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, TRUE, cb)) {
- status = WPAD_EBUSY;
- goto end;
- }
+BOOL IsBusyStream(s32 chan) {
+ BOOL enable;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u8 stop;
+ u32 devType;
+ u8 bufNum;
+ u16 qSize;
+ u16 notAck;
+ u8 frames;
+ s8 cmdNum;
+ u8 linkNum;
+
+ enable = OSDisableInterrupts();
+ stop = p_wpd->radioQuality;
+ devType = p_wpd->devType;
+ bufNum = WUDGetBufferStatus();
+ cmdNum = __wpadGetQueueSize(&p_wpd->stdCmdQueue);
+ qSize = __wpadGetBTEBufferStatus(chan);
+ notAck = __wpadGetBTMBufferStatus(chan);
+ frames = p_wpd->audioFrames;
+ linkNum = _WUDGetLinkNumber();
+ OSRestoreInterrupts(enable);
+
+ if ((stop) || (notAck > 3) || (bufNum == 10) || (bufNum >= linkNum * 2 + 2) || (devType == WPAD_DEV_INITIALIZING) ||
+ (cmdNum >= WPAD_COMMAND_CMD_MAX_LEN - 3) || (frames >= 1)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
- return WPAD_ESUCCESS;
- case WPAD_SPEAKER_UNMUTE:
- if (!WPADiSendMuteSpeaker(&p_wpd->stdCmdQueue, FALSE, cb)) {
- status = WPAD_EBUSY;
- goto end;
- }
+BOOL WPADCanSendStreamData(s32 chan) {
+ BOOL enable;
+ BOOL setup;
+ s32 status;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
- return WPAD_ESUCCESS;
- case WPAD_SPEAKER_PLAY:
- if (!WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 0x01, WM_REG_SPEAKER_08, cb)) {
- status = WPAD_EBUSY;
- goto end;
- }
+ enable = OSDisableInterrupts();
+ status = p_wpd->status;
+ setup = p_wpd->handshakeFinished;
+ OSRestoreInterrupts(enable);
- return WPAD_ESUCCESS;
- }
+ if ((status == WPAD_ERR_NO_CONTROLLER) || (setup == FALSE) || (IsBusyStream(chan))) {
+ return FALSE;
+ } else {
+ return TRUE;
}
-
-end:
- if (cb)
- (*cb)(chan, status);
-
- return status;
}
BOOL __wpadIsBusyStream(s32 chan) {
BOOL intrStatus;
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
+ WPADControlBlock* p_wpd = _wpdcb[chan];
u8 radioQuality;
u32 devType;
u8 bufferStatus;
@@ -250,185 +2274,268 @@ BOOL __wpadIsBusyStream(s32 chan) {
}
}
+BOOL WPADiSendStreamData(WPADCmdQueue* queue, void* p_buf, u16 len) {
+ WPADCommand cmd;
+ BOOL result;
+ u8 length = (u8)(len << 3);
+ ASSERTLINE(5873, len > 0 && len <= 20);
+
+ cmd.command = WPAD_HIDREP_STRM;
+ cmd.len = 21;
+ cmd.data[0] = length;
+ cmd.callback = NULL;
+ memcpy(cmd.data + 1, p_buf, len);
+ result = __wpadPushCommand(queue, cmd);
+ return result;
+}
+
s32 WPADSendStreamData(s32 chan, void* p_buf, u16 len) {
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
- BOOL intrStatus;
- BOOL handshakeFinished;
+ BOOL busy;
+ BOOL enable;
+ BOOL setup;
s32 status;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
ASSERTLINE(4528, p_buf != NULL);
ASSERTLINE(4529, len >= 0 && len <= 20);
- intrStatus = OSDisableInterrupts();
-
+ enable = OSDisableInterrupts();
status = p_wpd->status;
- handshakeFinished = p_wpd->handshakeFinished;
-
- OSRestoreInterrupts(intrStatus);
-
- if (status == WPAD_ENODEV)
- return WPAD_ENODEV;
-
- if (!handshakeFinished)
- return WPAD_EBUSY;
+ setup = p_wpd->handshakeFinished;
+ OSRestoreInterrupts(enable);
- if (__wpadIsBusyStream(chan))
- return WPAD_EBUSY;
-
- if (!WPADiSendStreamData(&p_wpd->stdCmdQueue, p_buf, len))
- return WPAD_EBUSY;
+ if (status == WPAD_ERR_NO_CONTROLLER) {
+ return WPAD_ERR_NO_CONTROLLER;
+ }
- intrStatus = OSDisableInterrupts();
+ if (!setup) {
+ return WPAD_ERR_BUSY;
+ }
- ++p_wpd->audioFrames;
+ if (IsBusyStream(chan)) {
+ return WPAD_ERR_BUSY;
+ }
- OSRestoreInterrupts(intrStatus);
+ if (!WPADiSendStreamData(&p_wpd->stdCmdQueue, p_buf, len)) {
+ return WPAD_ERR_BUSY;
+ }
+ enable = OSDisableInterrupts();
+ p_wpd->audioFrames++;
+ OSRestoreInterrupts(enable);
+ return WPAD_ERR_OK;
+}
- return WPAD_ESUCCESS;
+u8 WPADGetDpdSensitivity() {
+ return _dpdSensitivity;
}
-BOOL WPADiSendEnableSpeaker(struct WPADCmdQueue* cmdQueue, BOOL enabled, WPADCallback cb) {
- BOOL success;
- struct WPADCmd cmdBlk;
- cmdBlk.reportID = RPTID_ENABLE_SPEAKER;
- cmdBlk.dataLength = RPT14_SIZE;
- cmdBlk.dataBuf[RPT14_SPEAKER_ENABLE] = enabled ? 4 : 0;
- cmdBlk.cmdCB = cb;
+BOOL WPADIsDpdEnabled(s32 chan) {
+ BOOL state;
+ BOOL enable;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
- success = __wpadPushCommand(cmdQueue, cmdBlk);
- return success;
+ enable = OSDisableInterrupts();
+ state = p_wpd->info.dpd;
+ OSRestoreInterrupts(enable);
+ return state;
}
-BOOL WPADiSendGetContStat(struct WPADCmdQueue* cmdQueue, WPADInfo* infoOut, WPADCallback cb) {
- BOOL success;
- struct WPADCmd cmdBlk;
- cmdBlk.reportID = RPTID_REQUEST_STATUS;
- cmdBlk.dataLength = RPT15_SIZE;
- cmdBlk.dataBuf[0] = 0;
- cmdBlk.cmdCB = cb;
- cmdBlk.statusReportOut = infoOut;
+BOOL WPADiSendEnableDPD(WPADCmdQueue* queue, BOOL enable, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
- success = __wpadPushCommand(cmdQueue, cmdBlk);
- return success;
-}
+ cmd.command = WPAD_HIDREP_ENDPD;
+ cmd.len = 1;
+ cmd.data[0] = (u8)((enable) ? (u8)4 : (u8)0);
+ cmd.callback = callback;
-BOOL WPADiSendWriteDataCmd(struct WPADCmdQueue* cmdQueue, u8 cmd, u32 address, WPADCallback cb) {
- return WPADiSendWriteData(cmdQueue, &cmd, sizeof(cmd), address, cb);
+ return __wpadPushCommand(queue, cmd);
}
-BOOL WPADiSendWriteData(struct WPADCmdQueue* cmdQueue, void const* p_buf, u16 len, u32 address,
- WPADCallback cb) {
- BOOL success;
- u8 packedLen = len & 0x1f;
- struct WPADCmd cmdBlk;
-
- ASSERTLINE(5830, len > 0 && len <= 16);
- ASSERTLINE(5831, p_buf != NULL);
+s32 WPADControlDpd(s32 chan, u32 command, WPADCallback callback) {
+ BOOL enable;
+ BOOL dpd;
+ BOOL setup;
+ s32 result;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ static const u8 cfg1[5][9] = {
+ 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x64, 0x00,
+ 0xfe, 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x96,
+ 0x00, 0xb4, 0x02, 0x00, 0x00, 0x71, 0x01, 0x00,
+ 0xaa, 0x00, 0x64, 0x02, 0x00, 0x00, 0x71, 0x01,
+ 0x00, 0xc8, 0x00, 0x36, 0x07, 0x00, 0x00, 0x71,
+ 0x01, 0x00, 0x72, 0x00, 0x20,
+ };
+ static const u8 cfg2[5][2] = {
+ 0xfd, 0x05, 0xb3, 0x04, 0x63, 0x03, 0x35, 0x03,
+ 0x1f, 0x03,
+ };
+
+ enable = OSDisableInterrupts();
+ dpd = p_wpd->info.dpd;
+ result = p_wpd->status;
+ setup = p_wpd->handshakeFinished;
+ OSRestoreInterrupts(enable);
+
+ if (result != WPAD_ERR_NO_CONTROLLER) {
+ if (!setup) {
+ result = WPAD_ERR_BUSY;
+ } else if (command == 0) {
+ if (!dpd) {
+ result = WPAD_ERR_OK;
+ } else {
+ enable = OSDisableInterrupts();
+
+ if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 3)) {
+ WPADiSendEnableDPD(&p_wpd->stdCmdQueue, FALSE, NULL);
+ WPADiSendDPDCSB(&p_wpd->stdCmdQueue, FALSE, NULL);
+#if SDK_AUG2010
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, callback);
+#else
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, 0, callback);
+#endif
+
+ OSRestoreInterrupts(enable);
+ return WPAD_ERR_OK;
+ } else {
+ result = WPAD_ERR_BUSY;
+ }
+
+ OSRestoreInterrupts(enable);
+ }
+ } else {
+ enable = OSDisableInterrupts();
+
+ if (WPADiIsAvailableCmdQueue(&p_wpd->stdCmdQueue, 8)) {
+ WPADiSendEnableDPD(&p_wpd->stdCmdQueue, TRUE, NULL);
+ WPADiSendDPDCSB(&p_wpd->stdCmdQueue, TRUE, NULL);
+#if SDK_AUG2010
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, NULL);
+#else
+ WPADiSendGetContStat(&p_wpd->stdCmdQueue, NULL, WM_REG_DPD_30, NULL);
+#endif
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 1, WM_REG_DPD_30, NULL);
+ WPADiSendWriteData(&p_wpd->stdCmdQueue, (void*)cfg1[_dpdSensitivity - 1], 9,
+ WM_REG_DPD_CONFIG_BLOCK_1, NULL);
+ WPADiSendWriteData(&p_wpd->stdCmdQueue, (void*)cfg2[_dpdSensitivity - 1], 2,
+ WM_REG_DPD_CONFIG_BLOCK_2, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, (u8)command,
+ WM_REG_DPD_DATA_FORMAT, NULL);
+ WPADiSendWriteDataCmd(&p_wpd->stdCmdQueue, 8, WM_REG_DPD_30, callback);
+
+ OSRestoreInterrupts(enable);
+ return WPAD_ERR_OK;
+ } else {
+ result = WPAD_ERR_BUSY;
+ }
+ OSRestoreInterrupts(enable);
+ }
+ }
- cmdBlk.reportID = RPTID_WRITE_DATA;
- cmdBlk.dataLength = RPT16_SIZE;
- cmdBlk.cmdCB = cb;
- memcpy(&cmdBlk.dataBuf[RPT16_DATA_DST_ADDRESS], &address, sizeof address);
- memcpy(&cmdBlk.dataBuf[RPT16_DATA_LENGTH], &packedLen, sizeof packedLen);
- memcpy(&cmdBlk.dataBuf[RPT16_DATA], p_buf, len);
+ if (callback) {
+ callback(chan, result);
+ }
- success = __wpadPushCommand(cmdQueue, cmdBlk);
- return success;
+ return result;
}
-BOOL WPADiSendStreamData(struct WPADCmdQueue* cmdQueue, void const* p_buf, u16 len) {
- BOOL success;
- u8 packedLen = len << 3;
- struct WPADCmd cmdBlk;
+BOOL WPADiSendSetReportType(WPADCmdQueue* queue, u32 fmt, WPADCallback callback) {
+ WPADCommand cmd;
+ BOOL result;
- ASSERTLINE(5873, len > 0 && len <= 20);
+ cmd.command = WPAD_HIDREP_REPTYPE;
+ cmd.len = 2;
+ cmd.data[0] = 4;
+ cmd.callback = callback;
- cmdBlk.reportID = RPTID_SEND_SPEAKER_DATA;
- cmdBlk.dataLength = sizeof cmdBlk.dataBuf;
- cmdBlk.dataBuf[RPT18_DATA_LENGTH] = packedLen;
- cmdBlk.cmdCB = NULL;
- memcpy(&cmdBlk.dataBuf[RPT18_DATA], p_buf, len);
+ switch (fmt) {
+ case WPAD_FMT_CORE_BTN:
+ cmd.data[1] = RPTID_DATA_BTN;
+ break;
+ case WPAD_FMT_CORE_BTN_ACC:
+ cmd.data[1] = RPTID_DATA_BTN_ACC;
+ break;
+ case WPAD_FMT_CORE_BTN_ACC_DPD:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_DPD12;
+ break;
+ case WPAD_FMT_FS_BTN:
+ cmd.data[1] = RPTID_DATA_BTN_EXT8;
+ break;
+ case WPAD_FMT_FS_BTN_ACC:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_EXT16;
+ break;
+ case WPAD_FMT_FS_BTN_ACC_DPD:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_DPD10_EXT9;
+ break;
+ case WPAD_FMT_CLASSIC_BTN:
+ cmd.data[1] = RPTID_DATA_BTN_EXT8;
+ break;
+ case WPAD_FMT_CLASSIC_BTN_ACC:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_EXT16;
+ break;
+ case WPAD_FMT_CLASSIC_BTN_ACC_DPD:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_DPD10_EXT9;
+ break;
+ case WPAD_FMT_BTN_ACC_DPD_EXTENDED:
+ cmd.data[1] = RPTID_DATA_BTN_ACC_DPD18_1;
+ break;
+ }
- success = __wpadPushCommand(cmdQueue, cmdBlk);
- return success;
+ return __wpadPushCommand(queue, cmd);
}
-BOOL WPADiSendMuteSpeaker(struct WPADCmdQueue* cmdQueue, BOOL muted, WPADCallback cb) {
- BOOL success;
- struct WPADCmd cmdBlk;
+void WPADGetAddress(s32 chan, u8* addr) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ BOOL enable;
+ s8 handle;
+ u8* devAddr;
- cmdBlk.reportID = RPTID_MUTE_SPEAKER;
- cmdBlk.dataLength = RPT19_SIZE;
- cmdBlk.dataBuf[RPT19_SPEAKER_MUTE] = muted ? 4 : 0;
- cmdBlk.cmdCB = cb;
-
- success = __wpadPushCommand(cmdQueue, cmdBlk);
- return success;
-}
+ enable = OSDisableInterrupts();
+ handle = p_wpd->devHandle;
+ OSRestoreInterrupts(enable);
-BOOL WPADiIsAvailableCmdQueue(struct WPADCmdQueue* cmdQueue, s8 num) {
- s8 queueSize = __wpadGetQueueSize(cmdQueue);
+ devAddr = _WUDGetDevAddr((u8)handle);
- if ((u32)(queueSize + num) <= cmdQueue->length - 1)
- return TRUE;
- else
- return FALSE;
+ if (devAddr) {
+ memcpy(addr, devAddr, 6);
+ } else {
+ memset(addr, 0, 6);
+ }
}
-static s8 __wpadGetQueueSize(struct WPADCmdQueue* cmdQueue) {
- BOOL intrStatus = OSDisableInterrupts();
-
- s8 queueRemaining = cmdQueue->indexIn - cmdQueue->indexOut;
-
- if (queueRemaining < 0)
- queueRemaining += cmdQueue->length;
-
- OSRestoreInterrupts(intrStatus);
- return queueRemaining;
+void WPADShutdown() {
+ return;
}
-static BOOL __wpadPushCommand(struct WPADCmdQueue* cmdQueue, struct WPADCmd cmdBlk) {
- BOOL intrStatus = OSDisableInterrupts();
+void __WPADShutdown() {
+ BOOL enable;
+ int i;
- if (cmdQueue->length - 1 == (u32)__wpadGetQueueSize(cmdQueue)) {
- OSRestoreInterrupts(intrStatus);
+ enable = OSDisableInterrupts();
- return FALSE;
+ if (_shutdown) {
+ OSRestoreInterrupts(enable);
+ return;
}
- memset(&cmdQueue->queue[cmdQueue->indexIn], 0, sizeof cmdQueue->queue[cmdQueue->indexIn]);
- memcpy(&cmdQueue->queue[cmdQueue->indexIn], &cmdBlk, sizeof cmdQueue->queue[cmdQueue->indexIn]);
+ _shutdown = 1;
+ WUDSetVisibility(0, 0);
- cmdQueue->indexIn = (u32)cmdQueue->indexIn == ((cmdQueue->length) - 1) ? 0 : cmdQueue->indexIn + 1;
+ for (i = 10; i < 14; i++) {
+ memset(&_scArray.info[i], 0, sizeof(SCBtDeviceInfoSingle));
+ }
- OSRestoreInterrupts(intrStatus);
- return TRUE;
+ WPADiShutdown(FALSE);
+ OSRestoreInterrupts(enable);
}
-static u16 __wpadGetBTEBufferStatus(s32 chan) {
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
- BOOL intrStatus = OSDisableInterrupts();
- s32 status = p_wpd->status;
- s8 dev_handle = p_wpd->devHandle;
-
- OSRestoreInterrupts(intrStatus);
-
- if (status == WPAD_ENODEV)
- return 0;
-
- return _WUDGetQueuedSize(dev_handle);
+void WPADiShutdown(BOOL exec) {
+ OSCancelAlarm(&_managerAlarm);
+ WUDSetHidRecvCallback(NULL);
+ WUDShutdown(exec);
}
-static u16 __wpadGetBTMBufferStatus(s32 chan) {
- wpad_cb_st* p_wpd = __rvl_p_wpadcb[chan];
- BOOL intrStatus = OSDisableInterrupts();
- s32 status = p_wpd->status;
- s8 dev_handle = p_wpd->devHandle;
-
- OSRestoreInterrupts(intrStatus);
-
- if (status == WPAD_ENODEV)
- return 0;
-
- return _WUDGetNotAckedSize(dev_handle);
+BOOL WPADCancelSyncDevice() {
+ return WUDCancelSyncDevice();
}
diff --git a/src/revolution/wpad/WPADEncrypt.c b/src/revolution/wpad/WPADEncrypt.c
new file mode 100644
index 0000000000..9852cc6162
--- /dev/null
+++ b/src/revolution/wpad/WPADEncrypt.c
@@ -0,0 +1,265 @@
+#include <revolution/wpad/__wpad.h>
+
+#include "cstring"
+
+static u8 SEED;
+static u8 NUM_A;
+static u8 NUM_B;
+static u8 NUM_C;
+
+static u8 base[0x2A] = {
+ 0xA8, 0x77, 0xA6, 0xE0, 0xF7, 0x43,
+ 0x5A, 0x35, 0x85, 0xE2, 0x72, 0x97,
+ 0x8F, 0xB7, 0x1A, 0x62, 0x87, 0x38,
+ 0x0D, 0x67, 0xC7, 0xBE, 0x4F, 0x3E,
+ 0x20, 0x76, 0x37, 0x8F, 0x68, 0xB7,
+ 0xA9, 0x26, 0x3F, 0x2B, 0x10, 0xE3,
+ 0x30, 0x7E, 0x90, 0x0E, 0x85, 0x0A,
+};
+static u8 tb[0x900] = {
+ 0x70, 0x51, 0x03, 0x86, 0x40, 0x0D, 0x4F, 0xEB, 0x3E, 0xCC, 0xD1, 0x87, 0x35, 0xBD, 0xF5, 0x0B,
+ 0x5E, 0xD0, 0xF8, 0xF2, 0xD5, 0xE2, 0x6C, 0x31, 0x0C, 0xAD, 0xFC, 0x21, 0xC3, 0x78, 0xC1, 0x06,
+ 0xC2, 0x4C, 0x55, 0xE6, 0x4A, 0x34, 0x48, 0x11, 0x1E, 0xDA, 0xE7, 0x1A, 0x84, 0xA0, 0x96, 0xA7,
+ 0xE3, 0x7F, 0xAF, 0x63, 0x9C, 0xFA, 0x23, 0x5B, 0x79, 0xC8, 0x9E, 0xBA, 0xB2, 0xC9, 0x22, 0x12,
+ 0x4B, 0xB3, 0xA1, 0xB6, 0x32, 0x49, 0xA2, 0xE1, 0x89, 0x39, 0x10, 0x66, 0xC5, 0x07, 0x8F, 0x54,
+ 0xEA, 0x91, 0xCA, 0x3F, 0xF9, 0x19, 0xF0, 0xD7, 0x46, 0xBC, 0x28, 0x1B, 0x61, 0xE8, 0x2F, 0x6A,
+ 0xAE, 0x9D, 0xF6, 0x4E, 0x09, 0x14, 0x77, 0x4D, 0xDB, 0x1F, 0x2E, 0x7B, 0x7C, 0xF1, 0x43, 0xA3,
+ 0x00, 0xB8, 0x13, 0x8C, 0x85, 0xB9, 0x29, 0x75, 0x88, 0xFD, 0xD2, 0x56, 0x1C, 0x50, 0x97, 0x41,
+ 0xE5, 0x3B, 0x60, 0xB5, 0xC0, 0x64, 0xEE, 0x98, 0xD6, 0x2D, 0x25, 0xA4, 0xAA, 0xCD, 0x7D, 0xA8,
+ 0x83, 0xC6, 0xAB, 0xBE, 0x44, 0x99, 0x26, 0x3C, 0xCE, 0x9F, 0xBF, 0xD3, 0xCB, 0x76, 0x7A, 0x7E,
+ 0x82, 0x01, 0x8A, 0x9A, 0x80, 0x1D, 0x0E, 0xB0, 0x5C, 0xD4, 0x38, 0x62, 0xF4, 0x30, 0xE0, 0x8E,
+ 0x53, 0xB7, 0x02, 0x57, 0xAC, 0xA6, 0x52, 0x0A, 0x6D, 0x92, 0x65, 0x17, 0x24, 0x33, 0x45, 0x72,
+ 0x74, 0xB1, 0xB4, 0xF7, 0x5D, 0xED, 0x2C, 0xFF, 0x47, 0x37, 0x5A, 0x90, 0xBB, 0xDF, 0x2A, 0x16,
+ 0x59, 0x95, 0xD9, 0xC4, 0x27, 0x67, 0x73, 0xC7, 0x68, 0xFE, 0xA5, 0xDD, 0x6B, 0x5F, 0x93, 0xD8,
+ 0xEC, 0x05, 0x3A, 0x8D, 0x6E, 0xFB, 0x3D, 0xA9, 0x69, 0x36, 0xF3, 0x94, 0xDE, 0xEF, 0x15, 0x6F,
+ 0x8B, 0x9B, 0x08, 0x0F, 0xDC, 0x81, 0x18, 0x20, 0x04, 0xE4, 0x71, 0xCF, 0xE9, 0x2B, 0x42, 0x58,
+ 0x01, 0xA0, 0xA9, 0x62, 0xD6, 0x3F, 0x85, 0xA7, 0xB6, 0xD4, 0xFA, 0x15, 0x66, 0x17, 0x09, 0xBD,
+ 0x5D, 0x14, 0x34, 0x26, 0x59, 0x72, 0x91, 0x54, 0x06, 0x4F, 0xF8, 0xB0, 0x5B, 0x74, 0x93, 0x99,
+ 0x8C, 0xF2, 0x45, 0xCD, 0xEA, 0x4E, 0xAD, 0x10, 0x4A, 0xE5, 0xCA, 0xEE, 0xDF, 0xC6, 0x6F, 0x9F,
+ 0x88, 0x8E, 0x02, 0xCC, 0x08, 0xA8, 0x77, 0x94, 0x6D, 0x21, 0xB1, 0x28, 0xE4, 0x39, 0x79, 0x96,
+ 0x60, 0x71, 0x81, 0x16, 0x2E, 0xE6, 0x78, 0xB9, 0xC4, 0x46, 0x9A, 0x42, 0xAE, 0xB7, 0x7C, 0x43,
+ 0xB3, 0x22, 0x1A, 0x86, 0xC2, 0x32, 0x3D, 0x2D, 0x9C, 0xD2, 0x29, 0xE9, 0x63, 0x9B, 0xD1, 0x31,
+ 0x38, 0x5E, 0x1E, 0x36, 0x41, 0xBB, 0x03, 0x18, 0x2B, 0x3E, 0xBF, 0x68, 0x61, 0xFC, 0x52, 0xC0,
+ 0xDE, 0xE0, 0x0A, 0x58, 0x13, 0x5A, 0x00, 0xBE, 0x1C, 0x90, 0x0E, 0x53, 0x12, 0xFD, 0xE2, 0x6E,
+ 0xBA, 0xCE, 0x24, 0x27, 0x44, 0x7F, 0x87, 0xA3, 0xA1, 0xD5, 0x50, 0x40, 0xE3, 0xF9, 0x83, 0xF7,
+ 0xC7, 0xA2, 0x35, 0xC8, 0xDB, 0x19, 0xAB, 0x2F, 0x11, 0x25, 0xED, 0x33, 0x9E, 0x55, 0xE1, 0x48,
+ 0xAF, 0x73, 0x84, 0xDA, 0x2A, 0xAA, 0x51, 0xEB, 0x9D, 0x95, 0xB2, 0xCB, 0xE7, 0x70, 0x80, 0xFE,
+ 0x4C, 0x65, 0x04, 0xEF, 0xC5, 0xF1, 0xC3, 0x3A, 0xB4, 0xF5, 0x5F, 0x23, 0x89, 0xDD, 0x30, 0xA5,
+ 0x8B, 0xD3, 0xF6, 0xDC, 0x4D, 0x64, 0xD7, 0xF0, 0x8F, 0xEC, 0x56, 0x37, 0x5C, 0xA4, 0x0D, 0x07,
+ 0x76, 0x8A, 0x2C, 0x0B, 0xB5, 0xD8, 0xC1, 0x1F, 0xE8, 0x3B, 0xF4, 0x4B, 0x1B, 0x47, 0x6C, 0x49,
+ 0x67, 0x7B, 0x92, 0xCF, 0x75, 0x7E, 0x20, 0xD9, 0x7D, 0x3C, 0x97, 0x7A, 0xD0, 0x05, 0x6B, 0x0F,
+ 0x1D, 0xFB, 0x82, 0x98, 0x57, 0x8D, 0xF3, 0x6A, 0xBC, 0xAC, 0xC9, 0xA6, 0xFF, 0xB8, 0x69, 0x0C,
+ 0x4C, 0x4D, 0x72, 0x07, 0x5A, 0x49, 0x33, 0x8D, 0xA2, 0xAB, 0x46, 0x3D, 0x63, 0x0D, 0xA0, 0x97,
+ 0xFF, 0xF0, 0xF5, 0xFA, 0xC0, 0xE9, 0xDB, 0x62, 0xE4, 0xE1, 0x74, 0x43, 0xDC, 0x86, 0x18, 0x29,
+ 0x37, 0xF4, 0x06, 0xE2, 0xED, 0x6F, 0x90, 0x48, 0x1E, 0x2D, 0x1D, 0xEA, 0x73, 0x94, 0x54, 0xDF,
+ 0x25, 0xF6, 0x47, 0x27, 0xD9, 0x11, 0x77, 0xC9, 0x84, 0x1C, 0x5B, 0x5C, 0x51, 0x81, 0xA6, 0x22,
+ 0x3E, 0x24, 0x96, 0xC8, 0x8A, 0xEC, 0x82, 0x7C, 0x09, 0xB8, 0x45, 0x4A, 0x57, 0xBB, 0x2F, 0x50,
+ 0x75, 0x8E, 0x61, 0x70, 0x8C, 0x6C, 0xAF, 0xD0, 0xFD, 0xB4, 0x1B, 0xAE, 0xDE, 0xFE, 0x3B, 0xB5,
+ 0x36, 0xBD, 0x55, 0x01, 0x0E, 0x9C, 0x41, 0x56, 0x5F, 0xB3, 0x26, 0x03, 0x83, 0xBA, 0x13, 0x4B,
+ 0xCA, 0xC5, 0x0A, 0xF8, 0x60, 0xA5, 0xB9, 0xC7, 0xC3, 0x98, 0x32, 0xFB, 0x12, 0xF9, 0xA7, 0x92,
+ 0xAA, 0x68, 0xF3, 0x78, 0x7E, 0x05, 0x20, 0x21, 0x02, 0xE8, 0xBF, 0xF2, 0xB0, 0x59, 0x8F, 0xD2,
+ 0xCB, 0x87, 0x65, 0x15, 0xF1, 0x1A, 0xB2, 0x30, 0xAD, 0xEE, 0x58, 0xA3, 0x8B, 0x66, 0x1F, 0x2C,
+ 0xD7, 0x5D, 0x19, 0x85, 0xA8, 0xE6, 0xD3, 0x6B, 0xA1, 0x0C, 0x91, 0x93, 0x6A, 0x5E, 0x0B, 0x79,
+ 0xE3, 0xDD, 0x00, 0x4F, 0x3C, 0x89, 0x6E, 0x71, 0x69, 0xA9, 0xAC, 0x40, 0xE5, 0x99, 0x28, 0xC6,
+ 0x31, 0x4E, 0x7A, 0xCD, 0x08, 0x9E, 0x7D, 0xEF, 0x17, 0xFC, 0x88, 0xD8, 0xA4, 0x6D, 0x44, 0x95,
+ 0xD1, 0xB7, 0xD4, 0x9B, 0xBE, 0x2A, 0x34, 0x64, 0x2B, 0xCF, 0x2E, 0xEB, 0x38, 0xCE, 0x23, 0xE0,
+ 0x3A, 0x3F, 0xF7, 0x7B, 0x9F, 0x10, 0x53, 0xBC, 0x52, 0x67, 0x16, 0xE7, 0x80, 0x76, 0x04, 0xC4,
+ 0xB6, 0xC1, 0xC2, 0x7F, 0x9A, 0xDA, 0xD5, 0x39, 0x42, 0x14, 0x9D, 0xB1, 0x0F, 0x35, 0xD6, 0xCC,
+ 0xB9, 0xDA, 0x38, 0x0C, 0xA2, 0x9C, 0x09, 0x1F, 0x06, 0xB1, 0xB6, 0xFD, 0x1A, 0x69, 0x23, 0x30,
+ 0xC4, 0xDE, 0x01, 0xD1, 0xF4, 0x58, 0x29, 0x37, 0x1C, 0x7D, 0xD5, 0xBF, 0xFF, 0xBD, 0xC8, 0xC9,
+ 0xCF, 0x65, 0xBE, 0x7B, 0x78, 0x97, 0x98, 0x67, 0x08, 0xB3, 0x26, 0x57, 0xF7, 0xFA, 0x40, 0xAD,
+ 0x8E, 0x75, 0xA6, 0x7C, 0xDB, 0x91, 0x8B, 0x51, 0x99, 0xD4, 0x17, 0x7A, 0x90, 0x8D, 0xCE, 0x63,
+ 0xCB, 0x4E, 0xA0, 0xAB, 0x18, 0x3A, 0x5B, 0x50, 0x7F, 0x21, 0x74, 0xC1, 0xBB, 0xB8, 0xB7, 0xBA,
+ 0x0B, 0x35, 0x95, 0x31, 0x59, 0x9A, 0x4D, 0x04, 0x07, 0x1E, 0x5A, 0x76, 0x13, 0xF3, 0x71, 0x83,
+ 0xF0, 0x86, 0x03, 0xA8, 0x39, 0x42, 0xAA, 0x28, 0xE6, 0xE4, 0xD8, 0x5D, 0xD3, 0xD0, 0x6E, 0x6F,
+ 0x96, 0xFB, 0x5E, 0xBC, 0x56, 0xC2, 0x5F, 0x85, 0x9B, 0xE7, 0xAF, 0xD2, 0x3B, 0x84, 0x6A, 0xA7,
+ 0x53, 0xC5, 0x44, 0x49, 0xA5, 0xF9, 0x36, 0x72, 0x3D, 0x2C, 0xD9, 0x1B, 0xA1, 0xF5, 0x4F, 0x93,
+ 0x9D, 0x68, 0x47, 0x41, 0x16, 0xCA, 0x2A, 0x4C, 0xA3, 0x87, 0xD6, 0xE5, 0x19, 0x2E, 0x77, 0x15,
+ 0x6D, 0x70, 0xC0, 0xDF, 0xB2, 0x00, 0x46, 0xED, 0xC6, 0x6C, 0x43, 0x60, 0x92, 0x2D, 0xA9, 0x22,
+ 0x45, 0x8F, 0x34, 0x55, 0xAE, 0xA4, 0x0A, 0x66, 0x32, 0xE0, 0xDC, 0x02, 0xAC, 0xE8, 0x20, 0x8C,
+ 0x89, 0x62, 0x4A, 0xFE, 0xEE, 0xC3, 0xE3, 0x3C, 0xF1, 0x79, 0x05, 0xE9, 0xF6, 0x27, 0x33, 0xCC,
+ 0xF2, 0x9E, 0x11, 0x81, 0x7E, 0x80, 0x10, 0x8A, 0x82, 0x9F, 0x48, 0x0D, 0xD7, 0xB4, 0xFC, 0x2F,
+ 0xB5, 0xC7, 0xDD, 0x88, 0x14, 0x6B, 0x2B, 0x54, 0xEA, 0x1D, 0x94, 0x5C, 0xB0, 0xEF, 0x12, 0x24,
+ 0xCD, 0xEB, 0xE1, 0xE2, 0x64, 0x73, 0x3F, 0x0E, 0x52, 0x61, 0x25, 0x3E, 0xF8, 0x0F, 0x4B, 0xEC,
+ 0xC0, 0x00, 0x30, 0xF6, 0x02, 0x49, 0x3D, 0x10, 0x6E, 0x20, 0xC9, 0xA6, 0x2F, 0xFE, 0x2C, 0x2B,
+ 0x75, 0x2E, 0x45, 0x26, 0xAB, 0x48, 0xA9, 0x80, 0xFC, 0x04, 0xCC, 0xD3, 0xB5, 0xBA, 0xA3, 0x38,
+ 0x31, 0x7D, 0x01, 0xD9, 0xA7, 0x7B, 0x96, 0xB6, 0x63, 0x69, 0x4E, 0xF7, 0xDE, 0xE0, 0x78, 0xCA,
+ 0x50, 0xAA, 0x41, 0x91, 0x65, 0x88, 0xE4, 0x21, 0x85, 0xDA, 0x3A, 0x27, 0xBE, 0x1C, 0x3E, 0x42,
+ 0x5E, 0x17, 0x52, 0x7F, 0x1F, 0x89, 0x24, 0x6F, 0x8F, 0x5C, 0x67, 0x74, 0x0E, 0x12, 0x87, 0x8D,
+ 0xE9, 0x34, 0xED, 0x73, 0xC4, 0xF8, 0x61, 0x5B, 0x05, 0xDF, 0x59, 0x4C, 0x97, 0x79, 0x83, 0x18,
+ 0xA4, 0x55, 0x95, 0xEB, 0xBD, 0x53, 0xF5, 0xF1, 0x57, 0x66, 0x46, 0x9F, 0xB2, 0x81, 0x09, 0x51,
+ 0x86, 0x22, 0x16, 0xDD, 0x23, 0x93, 0x76, 0x29, 0xC2, 0xD7, 0x1D, 0xD4, 0xBF, 0x36, 0x3F, 0xEA,
+ 0x4B, 0x11, 0x32, 0xB9, 0x62, 0x54, 0x60, 0xD6, 0x6D, 0x43, 0x9A, 0x0D, 0x92, 0x9C, 0xB0, 0xEF,
+ 0x58, 0x6C, 0x9D, 0x77, 0x2D, 0x70, 0xFA, 0xF3, 0xB3, 0x0B, 0xE2, 0x40, 0x7E, 0xF4, 0x8A, 0xE5,
+ 0x8C, 0x3C, 0x56, 0x71, 0xD1, 0x64, 0xE1, 0x82, 0x0A, 0xCB, 0x13, 0x15, 0x90, 0xEC, 0x03, 0x99,
+ 0xAF, 0x14, 0x5D, 0x0F, 0x33, 0x4A, 0x94, 0xA5, 0xA8, 0x35, 0x1B, 0xE3, 0x6A, 0xC6, 0x28, 0xFF,
+ 0x4D, 0xE7, 0x25, 0x84, 0xAC, 0x08, 0xAE, 0xC5, 0xA2, 0x2A, 0xB8, 0x37, 0x0C, 0x7A, 0xA0, 0xC3,
+ 0xCE, 0xAD, 0x06, 0x1A, 0x9E, 0x8B, 0xFB, 0xD5, 0xF0, 0xC1, 0x1E, 0xD0, 0xB4, 0x9B, 0xB1, 0x44,
+ 0xF2, 0x47, 0xC7, 0x68, 0xCF, 0x72, 0xBB, 0x4F, 0x5A, 0xF9, 0xDC, 0x6B, 0xDB, 0xD2, 0xE8, 0x7C,
+ 0xC8, 0xEE, 0x98, 0xA1, 0xE6, 0xD8, 0x39, 0x07, 0x5F, 0xFD, 0x8E, 0x19, 0xB7, 0x3B, 0xBC, 0xCD,
+ 0x7C, 0xE3, 0x81, 0x73, 0xB2, 0x11, 0xBF, 0x6F, 0x20, 0x98, 0xFE, 0x75, 0x96, 0xEF, 0x6C, 0xDA,
+ 0x50, 0xE1, 0x09, 0x72, 0x54, 0x45, 0xBA, 0x34, 0x80, 0x5B, 0xED, 0x3E, 0x53, 0x2C, 0x87, 0xA4,
+ 0x57, 0xF3, 0x33, 0x3F, 0x3C, 0xB7, 0x67, 0xB4, 0xA3, 0x25, 0x60, 0x4F, 0x07, 0x6B, 0x1B, 0x47,
+ 0x15, 0x0F, 0xE4, 0x0A, 0xEA, 0xD1, 0x32, 0x78, 0x36, 0x49, 0x8D, 0x4B, 0xD2, 0xBC, 0xA5, 0xDC,
+ 0x1D, 0x0D, 0x4D, 0xCD, 0x9A, 0x82, 0x5F, 0xFC, 0x94, 0x65, 0xBE, 0xE2, 0xF4, 0xC9, 0x1E, 0x44,
+ 0xCB, 0x9E, 0x0C, 0x64, 0x71, 0x26, 0x63, 0xB3, 0x14, 0xE8, 0x40, 0x70, 0x8A, 0x0E, 0x19, 0x42,
+ 0x6D, 0xAC, 0x88, 0x10, 0x5C, 0xDF, 0x41, 0xA9, 0xAD, 0xE5, 0xFB, 0x74, 0xCC, 0xD5, 0x06, 0x8E,
+ 0x59, 0x86, 0xCE, 0x1F, 0x3D, 0x76, 0xE0, 0x8F, 0xB9, 0x77, 0x27, 0x7B, 0xA6, 0xD8, 0x29, 0xD3,
+ 0xEC, 0xB8, 0x13, 0xF7, 0xFA, 0xC3, 0x51, 0x6A, 0xDE, 0x4A, 0x5A, 0xEB, 0xC2, 0x8B, 0x23, 0x48,
+ 0x92, 0xCF, 0x62, 0xA8, 0x99, 0xF8, 0xD0, 0x2E, 0x85, 0x61, 0x43, 0xC8, 0xBD, 0xF0, 0x05, 0x93,
+ 0xCA, 0x4E, 0xF1, 0x7D, 0x30, 0xFD, 0xC4, 0x69, 0x66, 0x2F, 0x08, 0xB1, 0x52, 0xF9, 0x21, 0xE6,
+ 0x7A, 0x2B, 0xDD, 0x39, 0x84, 0xFF, 0xC0, 0x91, 0xD6, 0x37, 0xD4, 0x7F, 0x2D, 0x9B, 0x5D, 0xA1,
+ 0x3B, 0x6E, 0xB5, 0xC5, 0x46, 0x04, 0xF5, 0x90, 0xEE, 0x7E, 0x83, 0x1C, 0x03, 0x56, 0xB6, 0xAA,
+ 0x00, 0x17, 0x01, 0x35, 0x55, 0x79, 0x0B, 0x12, 0xBB, 0x1A, 0x31, 0xE7, 0x02, 0x28, 0x16, 0xC1,
+ 0xF6, 0xA2, 0xDB, 0x18, 0x9C, 0x89, 0x68, 0x38, 0x97, 0xAB, 0xC7, 0x2A, 0xD7, 0x3A, 0xF2, 0xC6,
+ 0x24, 0x4C, 0xB0, 0x58, 0xA0, 0x22, 0x5E, 0x9D, 0xD9, 0xA7, 0xE9, 0xAE, 0xAF, 0x8C, 0x95, 0x9F,
+ 0x28, 0xB7, 0x20, 0xD7, 0xB0, 0x30, 0xC3, 0x09, 0x19, 0xC0, 0x67, 0xD6, 0x00, 0x3C, 0x7E, 0xE7,
+ 0xE9, 0xF4, 0x08, 0x5A, 0xF8, 0xB8, 0x2E, 0x05, 0xA6, 0x25, 0x9E, 0x5C, 0xD8, 0x15, 0x0D, 0xE1,
+ 0xF6, 0x11, 0x54, 0x6B, 0xCD, 0x21, 0x46, 0x66, 0x5E, 0x84, 0xAD, 0x06, 0x38, 0x29, 0x44, 0xC5,
+ 0xA2, 0xCE, 0xF1, 0xAA, 0xC1, 0x40, 0x71, 0x86, 0xB5, 0xEF, 0xFC, 0x36, 0xA8, 0xCB, 0x0A, 0x48,
+ 0x27, 0x45, 0x64, 0xA3, 0xAF, 0x8C, 0xB2, 0xC6, 0x9F, 0x07, 0x89, 0xDC, 0x17, 0xD3, 0x49, 0x79,
+ 0xFB, 0xFE, 0x1D, 0xD0, 0xB9, 0x88, 0x43, 0x52, 0xBC, 0x01, 0x78, 0x2B, 0x7D, 0x94, 0xC7, 0x0E,
+ 0xDE, 0xA5, 0xD5, 0x9B, 0xCC, 0xF7, 0x61, 0x7A, 0xC2, 0x74, 0x81, 0x39, 0x03, 0xAB, 0x96, 0xA0,
+ 0x37, 0xBD, 0x2D, 0x72, 0x75, 0x3F, 0xC9, 0xD4, 0x8E, 0x6F, 0xF9, 0x8D, 0xED, 0x62, 0xDB, 0x1C,
+ 0xDF, 0x04, 0xAC, 0x1B, 0x6C, 0x14, 0x4B, 0x63, 0xF0, 0xBF, 0xB4, 0x82, 0xEC, 0x7B, 0x1A, 0x59,
+ 0x92, 0xD2, 0x10, 0x60, 0xB6, 0x3D, 0x5F, 0xE6, 0x80, 0x6E, 0x70, 0xC4, 0xF2, 0x35, 0xD9, 0x7C,
+ 0xEE, 0xE5, 0x41, 0xA4, 0x5B, 0x50, 0xDD, 0xBB, 0x4C, 0xF3, 0x1F, 0x9D, 0x5D, 0x57, 0x55, 0x51,
+ 0x97, 0xE3, 0x58, 0x42, 0x4D, 0x9C, 0x73, 0xBA, 0xC8, 0x77, 0x31, 0x69, 0x26, 0xAE, 0xEA, 0x8A,
+ 0xDA, 0x22, 0xB3, 0x87, 0x56, 0xFA, 0x93, 0x0B, 0x34, 0x16, 0x33, 0xE8, 0xE4, 0x53, 0xBE, 0xA9,
+ 0xB1, 0x3A, 0x3E, 0xF5, 0x90, 0x6A, 0xCF, 0x3B, 0x12, 0xFD, 0x8F, 0x9A, 0xA7, 0x47, 0x91, 0x99,
+ 0xEB, 0x0F, 0x24, 0xFF, 0x23, 0x18, 0x85, 0x4E, 0x7F, 0x0C, 0xE0, 0xA1, 0xE2, 0xD1, 0x2C, 0x2A,
+ 0x4A, 0x02, 0x4F, 0x1E, 0x95, 0x68, 0x8B, 0x98, 0x83, 0x6D, 0x76, 0xCA, 0x65, 0x32, 0x13, 0x2F,
+ 0xC3, 0x82, 0x9A, 0xA4, 0xBA, 0x81, 0x60, 0x37, 0x34, 0x35, 0xFC, 0x80, 0xA8, 0x51, 0x65, 0x67,
+ 0xED, 0x30, 0x5F, 0x10, 0xD3, 0x4A, 0x27, 0x2F, 0x13, 0xB9, 0x2A, 0xD2, 0xCC, 0xE1, 0xEF, 0xAE,
+ 0xEB, 0xBE, 0xF4, 0xBD, 0xCF, 0x43, 0xB3, 0xC5, 0x88, 0x84, 0xB7, 0xDD, 0x39, 0x40, 0xCE, 0x48,
+ 0x6D, 0x9B, 0x72, 0x61, 0x7E, 0xE7, 0xA1, 0x4E, 0x53, 0x2E, 0x77, 0x3B, 0xE2, 0xC9, 0x36, 0x22,
+ 0x1B, 0x6E, 0x73, 0xB1, 0x03, 0xB2, 0x4C, 0x87, 0xA9, 0xD4, 0x4D, 0x0F, 0xD8, 0x15, 0x6C, 0xAA,
+ 0x18, 0xF6, 0x49, 0x57, 0x5D, 0xFB, 0x7A, 0x14, 0x94, 0x63, 0xA0, 0x11, 0xB0, 0x9E, 0xDE, 0x05,
+ 0x46, 0xC8, 0xEE, 0x47, 0xDB, 0xDC, 0x24, 0x89, 0x9C, 0x91, 0x97, 0x29, 0xE9, 0x7B, 0xC1, 0x07,
+ 0x1E, 0xB8, 0xFD, 0xFE, 0xAC, 0xC6, 0x62, 0x98, 0x4F, 0xF1, 0x79, 0xE0, 0xE8, 0x6B, 0x78, 0x56,
+ 0xB6, 0x8D, 0x04, 0x50, 0x86, 0xCA, 0x6F, 0x20, 0xE6, 0xEA, 0xE5, 0x76, 0x17, 0x1C, 0x74, 0x7F,
+ 0xBC, 0x0D, 0x2C, 0x85, 0xF7, 0x66, 0x96, 0xE4, 0x8B, 0x75, 0x3F, 0x4B, 0xD9, 0x38, 0xAF, 0x7C,
+ 0xDA, 0x0B, 0x83, 0x2D, 0x31, 0x32, 0xA2, 0xF5, 0x1D, 0x59, 0x41, 0x45, 0xBF, 0x3C, 0x1F, 0xF8,
+ 0xF9, 0x8A, 0xD0, 0x16, 0x25, 0x69, 0x12, 0x99, 0x9D, 0x21, 0x95, 0xAB, 0x01, 0xA6, 0xD7, 0xB5,
+ 0xC0, 0x7D, 0xFF, 0x58, 0x0E, 0x3A, 0x92, 0xD1, 0x55, 0xE3, 0x08, 0x9F, 0xD6, 0x3E, 0x52, 0x8E,
+ 0xFA, 0xA3, 0xC7, 0x02, 0xCD, 0xDF, 0x8F, 0x64, 0x19, 0x8C, 0xF3, 0xA7, 0x0C, 0x5E, 0x0A, 0x6A,
+ 0x09, 0xF0, 0x93, 0x5B, 0x42, 0xC2, 0x06, 0x23, 0xEC, 0x71, 0xAD, 0xB4, 0xCB, 0xBB, 0x70, 0x28,
+ 0xD5, 0x1A, 0x5C, 0x33, 0x68, 0x5A, 0x00, 0x44, 0x90, 0xA5, 0xC4, 0x26, 0x3D, 0x2B, 0xF2, 0x54,
+ 0x96, 0xAD, 0xDA, 0x1F, 0xED, 0x33, 0xE1, 0x81, 0x69, 0x08, 0x0D, 0x0A, 0xDB, 0x35, 0x77, 0x9A,
+ 0x64, 0xD1, 0xFC, 0x78, 0xAA, 0x1B, 0xD0, 0x67, 0xA0, 0xDD, 0xFA, 0x6C, 0x63, 0x71, 0x05, 0x84,
+ 0x17, 0x6A, 0x89, 0x4F, 0x66, 0x7F, 0xC6, 0x50, 0x55, 0x92, 0x6F, 0xBD, 0xE7, 0xD2, 0x40, 0x72,
+ 0x8D, 0xBB, 0xEC, 0x06, 0x42, 0x8A, 0xE4, 0x88, 0x9D, 0x7E, 0x7A, 0x82, 0x27, 0x13, 0x41, 0x1A,
+ 0xAF, 0xC8, 0xA4, 0x76, 0xB4, 0xC2, 0xFE, 0x6D, 0x1C, 0xD9, 0x61, 0x30, 0xB3, 0x7C, 0xEA, 0xF7,
+ 0x29, 0x0F, 0xF2, 0x3B, 0x51, 0xC1, 0xDE, 0x5F, 0xE5, 0x2A, 0x2F, 0x99, 0x0B, 0x5D, 0xA3, 0x2B,
+ 0x4A, 0xAB, 0x95, 0xA5, 0xD3, 0x58, 0x56, 0xEE, 0x28, 0x31, 0x00, 0xCC, 0x15, 0x46, 0xCA, 0xE6,
+ 0x86, 0x38, 0x3C, 0x65, 0xF5, 0xE3, 0x9F, 0xD6, 0x5B, 0x09, 0x49, 0x83, 0x70, 0x2D, 0x53, 0xA9,
+ 0x7D, 0xE2, 0xC4, 0xAC, 0x8E, 0x5E, 0xB8, 0x25, 0xF4, 0xB9, 0x57, 0xF3, 0xF1, 0x68, 0x47, 0xB2,
+ 0xA2, 0x59, 0x20, 0xCE, 0x34, 0x79, 0x5C, 0x90, 0x0E, 0x1E, 0xBE, 0xD5, 0x22, 0x23, 0xB1, 0xC9,
+ 0x18, 0x62, 0x16, 0x2E, 0x91, 0x3E, 0x07, 0x8F, 0xD8, 0x3F, 0x93, 0x3D, 0xD4, 0x9B, 0xDF, 0x85,
+ 0x21, 0xFB, 0x11, 0x74, 0x97, 0xC7, 0xD7, 0xDC, 0x4C, 0x19, 0x45, 0x98, 0xE9, 0x43, 0x02, 0x4B,
+ 0xBC, 0xC3, 0x04, 0x9C, 0x6B, 0xF0, 0x75, 0x52, 0xA7, 0x26, 0xF6, 0xC5, 0xBA, 0xCF, 0xB0, 0xB7,
+ 0xAE, 0x5A, 0xA1, 0xBF, 0x03, 0x8B, 0x80, 0x12, 0x6E, 0x0C, 0xEB, 0xF9, 0xC0, 0x44, 0x24, 0xEF,
+ 0x10, 0xF8, 0xA8, 0x8C, 0xE8, 0x7B, 0xFF, 0x9E, 0x2C, 0xCD, 0x60, 0x36, 0x87, 0xB5, 0x94, 0xA6,
+ 0x54, 0x73, 0x3A, 0x14, 0x4E, 0x01, 0x1D, 0xB6, 0xFD, 0x37, 0x48, 0x4D, 0x39, 0xCB, 0xE0, 0x32,
+};
+
+static u8 random() {
+ SEED = (u8)(((u32)SEED * NUM_A + NUM_B) % NUM_C);
+ return SEED;
+}
+
+static u8 ror(u8 src, u8 rot) {
+ u8 ret;
+ u8 rt;
+
+ rt = (u8)(rot % 8);
+ ret = (u8)(src >> rt | src << (8 - rt));
+
+ return ret;
+}
+
+static u8 rol(u8 src, u8 rol) {
+ u8 ret;
+ u8 rl;
+
+ rl = (u8)(rol % 8);
+ ret = (u8)(src << rl | src >> (8 - rl));
+
+ return ret;
+}
+
+void WPADiCreateKey(s32 chan) {
+ BOOL enable;
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+
+ u8 idx;
+ u8 baseIdx;
+ u8 tblRnd[10];
+ u8 ft[8];
+ u8 sb[8];
+ u8 key[6];
+ u8 i;
+
+ SEED = (u8)((OSGetTick() >> 8) & 0xff);
+ NUM_A = (u8)((OSGetTick() >> 16) & 0x3f);
+ NUM_B = (u8)((OSGetTick() >> 24) & 0x4c);
+ NUM_C = 0xff;
+
+ idx = (u8)(random() % 7);
+ baseIdx = (u8)(idx * 6);
+
+ for (i = 0; i < 10; i++) {
+ tblRnd[i] = tb[random()];
+ }
+
+ enable = OSDisableInterrupts();
+ key[0] = (u8)((ror((u8)(base[baseIdx] ^ tb[tblRnd[5]]), tb[tblRnd[2]]) - tb[tblRnd[9]]) ^ tb[tblRnd[4]]);
+ key[1] = (u8)((ror((u8)(base[baseIdx + 1] ^ tb[tblRnd[1]]), tb[tblRnd[0]]) - tb[tblRnd[5]]) ^ tb[tblRnd[7]]);
+ key[2] = (u8)((ror((u8)(base[baseIdx + 2] ^ tb[tblRnd[6]]), tb[tblRnd[8]]) - tb[tblRnd[2]]) ^ tb[tblRnd[0]]);
+ key[3] = (u8)((ror((u8)(base[baseIdx + 3] ^ tb[tblRnd[4]]), tb[tblRnd[7]]) - tb[tblRnd[3]]) ^ tb[tblRnd[2]]);
+ key[4] = (u8)((ror((u8)(base[baseIdx + 4] ^ tb[tblRnd[1]]), tb[tblRnd[6]]) - tb[tblRnd[3]]) ^ tb[tblRnd[4]]);
+ key[5] = (u8)((ror((u8)(base[baseIdx + 5] ^ tb[tblRnd[7]]), tb[tblRnd[8]]) - tb[tblRnd[5]]) ^ tb[tblRnd[9]]);
+
+ ft[0] = (u8)(tb[(idx + 1) * 256 + key[4]] ^ tb[(idx + 2) * 256 + tblRnd[3]]);
+ ft[1] = (u8)(tb[(idx + 1) * 256 + key[2]] ^ tb[(idx + 2) * 256 + tblRnd[5]]);
+ ft[2] = (u8)(tb[(idx + 1) * 256 + key[5]] ^ tb[(idx + 2) * 256 + tblRnd[7]]);
+ ft[3] = (u8)(tb[(idx + 1) * 256 + key[0]] ^ tb[(idx + 2) * 256 + tblRnd[2]]);
+ ft[4] = (u8)(tb[(idx + 1) * 256 + key[1]] ^ tb[(idx + 2) * 256 + tblRnd[4]]);
+ ft[5] = (u8)(tb[(idx + 1) * 256 + key[3]] ^ tb[(idx + 2) * 256 + tblRnd[9]]);
+ ft[6] = (u8)(tb[(idx + 1) * 256 + tblRnd[0]] ^ tb[(idx + 2) * 256 + tblRnd[6]]);
+ ft[7] = (u8)(tb[(idx + 1) * 256 + tblRnd[1]] ^ tb[(idx + 2) * 256 + tblRnd[8]]);
+ sb[0] = (u8)(tb[(idx + 1) * 256 + key[0]] ^ tb[(idx + 2) * 256 + tblRnd[1]]);
+ sb[1] = (u8)(tb[(idx + 1) * 256 + key[5]] ^ tb[(idx + 2) * 256 + tblRnd[4]]);
+ sb[2] = (u8)(tb[(idx + 1) * 256 + key[3]] ^ tb[(idx + 2) * 256 + tblRnd[0]]);
+ sb[3] = (u8)(tb[(idx + 1) * 256 + key[2]] ^ tb[(idx + 2) * 256 + tblRnd[9]]);
+ sb[4] = (u8)(tb[(idx + 1) * 256 + key[4]] ^ tb[(idx + 2) * 256 + tblRnd[7]]);
+ sb[5] = (u8)(tb[(idx + 1) * 256 + key[1]] ^ tb[(idx + 2) * 256 + tblRnd[8]]);
+ sb[6] = (u8)(tb[(idx + 1) * 256 + tblRnd[3]] ^ tb[(idx + 2) * 256 + tblRnd[5]]);
+ sb[7] = (u8)(tb[(idx + 1) * 256 + tblRnd[2]] ^ tb[(idx + 2) * 256 + tblRnd[6]]);
+
+ for (i = 0; i < 10; i++) {
+ p_wpd->key[i] = tblRnd[9 - i];
+ }
+
+ for (i = 0; i < 6; i++) {
+ p_wpd->key[i + 10] = key[5 - i];
+ }
+
+ memcpy(p_wpd->ft, ft, 8);
+ memcpy(p_wpd->sb, sb, 8);
+ OSRestoreInterrupts(enable);
+}
+
+void WPADiDecode(s32 chan, void* p_buf, u16 len, u16 offset) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u8 idx;
+ u8* ptr;
+ u16 i;
+
+ ptr = (u8*)p_buf;
+
+ for (i = 0; i < len; i++) {
+ idx = (u8)((offset + i) % 8);
+ ptr[i] = (u8)((ptr[i] ^ p_wpd->sb[idx]) + p_wpd->ft[idx]);
+ }
+}
diff --git a/src/revolution/wpad/WPADHIDParser.c b/src/revolution/wpad/WPADHIDParser.c
new file mode 100644
index 0000000000..4b8b774b7c
--- /dev/null
+++ b/src/revolution/wpad/WPADHIDParser.c
@@ -0,0 +1,1667 @@
+#include <revolution/wpad.h>
+#include <revolution/wpad/__wpad.h>
+#include <cstring>
+
+extern void DEBUGPrint(const char*, ...);
+
+void __a1_20_status_report(u8 chan, u8* data);
+void __a1_21_user_data(u8 chan, u8* data);
+void __a1_22_ack(u8 chan, u8* data);
+void __a1_30_data_type(u8 chan, u8* data);
+void __a1_31_data_type(u8 chan, u8* data);
+void __a1_32_data_type(u8 chan, u8* data);
+void __a1_33_data_type(u8 chan, u8* data);
+void __a1_34_data_type(u8 chan, u8* data);
+void __a1_35_data_type(u8 chan, u8* data);
+void __a1_36_data_type(u8 chan, u8* data);
+void __a1_37_data_type(u8 chan, u8* data);
+void __a1_3d_data_type(u8 chan, u8* data);
+void __a1_3e_data_type(u8 chan, u8* data);
+void __a1_3f_data_type(u8 chan, u8* data);
+void __a1_unused_report(u8 chan, u8* data);
+
+#define HID_WPAD_BUTTON_MASK (u16)(0x9F1F)
+#define HID_WPAD_BUTTON_CLEAR (u16)(0x60E0)
+#define HID_NEAREMPTY_MASK (u8)(0x80)
+#define HID_DPD_MASK (u8)(0x8)
+#define HID_SPEAKER_MASK (u8)(0x4)
+#define HID_ATTACH_MASK (u8)(0x2)
+#define HID_LOWBAT_MASK (u8)(0x1)
+#define HID_LED_MASK (u8)(0xF0)
+#define HID_FW_MASK (u8)(0xF0)
+#define HID_PRT_MASK (u8)(0xF)
+
+#define HID_IDX_BYTE7 1
+#define HID_IDX_BYTE8 2
+#define HID_IDX_BYTE9 3
+#define HID_IDX_BYTE10 4
+#define HID_IDX_BYTE11 5
+#define HID_IDX_BYTE12 6
+#define HID_IDX_BYTE13 7
+#define HID_IDX_BYTE14 8
+#define HID_IDX_BYTE15 9
+#define HID_IDX_BYTE16 10
+#define HID_IDX_BYTE17 11
+#define HID_IDX_BYTE18 12
+#define HID_IDX_BYTE19 13
+#define HID_IDX_BYTE20 14
+#define HID_IDX_BYTE21 15
+#define HID_IDX_BYTE22 16
+#define HID_IDX_BYTE23 17
+#define HID_IDX_BYTE24 18
+#define HID_IDX_BYTE25 19
+#define HID_IDX_BYTE26 20
+#define HID_IDX_BYTE27 21
+
+void (*__a1_input_reports_array[])(u8 chan, u8* data) = {
+ __a1_20_status_report, __a1_21_user_data, __a1_22_ack, __a1_unused_report,
+ __a1_unused_report, __a1_unused_report, __a1_unused_report, __a1_unused_report,
+ __a1_unused_report, __a1_unused_report, __a1_unused_report, __a1_unused_report,
+ __a1_unused_report, __a1_unused_report, __a1_unused_report, __a1_unused_report,
+ __a1_30_data_type, __a1_31_data_type, __a1_32_data_type, __a1_33_data_type,
+ __a1_34_data_type, __a1_35_data_type, __a1_36_data_type, __a1_37_data_type,
+ __a1_unused_report, __a1_unused_report, __a1_unused_report, __a1_unused_report,
+ __a1_unused_report, __a1_3d_data_type, __a1_3e_data_type, __a1_3f_data_type
+};
+
+static u8 checkInvalidData[21] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+static u8 checkBuffer[21];
+
+WPADExtensionCallback initExtension(s32 chan, WPADControlBlock*);
+
+void abortInitExtension(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u32 type;
+
+ if (result != WPAD_ERR_OK) {
+ WPADiClearQueue(&p_wpd->extCmdQueue);
+
+ if (result == WPAD_ERR_NO_CONTROLLER) {
+ type = WPAD_DEV_NONE;
+ } else if (p_wpd->info.attach) {
+ type = WPAD_DEV_NOT_SUPPORTED;
+ } else {
+ type = WPAD_DEV_CORE;
+ }
+
+ p_wpd->devType = (u8)type;
+ if (p_wpd->extensionCallback) {
+ p_wpd->extensionCallback(chan, (s32)type);
+ }
+ }
+}
+
+#define PI 3.141592f
+
+// Copied from Petari - this is likely close to the correct implementation,
+// but loop unrolling is not happening so it ends up completely mismatching.
+// Not sure if it's supposed to be manually unrolled in code? But then the
+// bit-twiddling instructions end up mismatching.
+static inline void __parse_dpd_data(s32 chan, WPADStatus** p_status, u8 fmt, u8* p_data, u8 len) {
+ u8 i;
+ u8 x;
+ u8 y;
+ u8 xy;
+
+ if (fmt == WPAD_DPD_STANDARD) {
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; ++i) {
+ if (i * 3 + 2 < len) {
+ x = *(p_data + i * 3);
+ y = *(p_data + i * 3 + 1);
+ xy = *(p_data + i * 3 + 2);
+
+ (*p_status)->obj[i].x = (s16)((s16)((s16)(((u16)x) & 0xFF) | (u16)(((u16)xy & 0x30) << 4)));
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)y) & 0xFF) | (u16)(((u16)xy & 0xC0) << 2)));
+ (*p_status)->obj[i].size = (u16)(((xy & 0xF) & 0xFF));
+ (*p_status)->obj[i].size = (u8)((f32)((*p_status)->obj[i].size) * (f32)((*p_status)->obj[i].size) * PI);
+ if ((*p_status)->obj[i].size == 0 || (*p_status)->obj[i].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) ||
+ (*p_status)->obj[i].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1)) {
+ (*p_status)->obj[i].x = (s16)0;
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ (*p_status)->obj[i].size = 0;
+ }
+ (*p_status)->obj[i].traceId = i;
+ } else {
+ (*p_status)->obj[i].x = (s16)0;
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ (*p_status)->obj[i].size = 0;
+ (*p_status)->obj[i].traceId = i;
+ }
+ }
+ } else if (fmt == WPAD_DPD_BASIC) {
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; ++i) {
+ x = *(p_data + i * 3 - (i / 2));
+ y = *(p_data + i * 3 - (i / 2) + 1);
+ xy = *(p_data + (i / 2) * 5 + 2);
+
+ if ((i % 2) == 0) {
+ (*p_status)->obj[i].x = (s16)((s16)((s16)(((u16)x) & 0xFF) | (u16)(((u16)(xy & 0x30)) << 4)));
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)y) & 0xFF) | (u16)(((u16)(xy & 0xC0)) << 2)));
+ } else {
+ (*p_status)->obj[i].x = (s16)((s16)((s16)(((u16)x) & 0xFF) | (u16)(((u16)(xy & (u8)(0x30 >> 4))) << 8)));
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)y) & 0xFF) | (u16)(((u16)(xy & (u8)(0xC0 >> 4))) << 6)));
+ }
+ if ((*p_status)->obj[i].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) || (*p_status)->obj[i].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1)) {
+ (*p_status)->obj[i].x = (s16)0;
+ (*p_status)->obj[i].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ (*p_status)->obj[i].size = 0;
+ } else {
+ (*p_status)->obj[i].size = 12;
+ }
+ (*p_status)->obj[i].traceId = i;
+ }
+ }
+}
+
+void getDevConfig(s32 chan, s32 result, WPADStatus* p_status, u8* data) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u8* p_buf = p_wpd->wmReadDataPtr;
+ u8 checkSum;
+ u8 i;
+ int j;
+ int index;
+ DPDObject obj[WPAD_DPD_MAX_OBJECTS];
+ const s16 dummyObjX[] = {0x7F, 0x7F, 0x380, 0x380};
+ const s16 dummyObjY[] = {0x5D, 0x2A2, 0x2A2, 0x5D};
+
+ for (i = 0; i < WPAD_DPD_MAX_OBJECTS; i++) {
+ p_wpd->devConf.obj[i].x = dummyObjX[i];
+ p_wpd->devConf.obj[i].y = dummyObjY[i];
+ p_wpd->devConf.obj[i].size = (u16)p_wpd->dpdDummyObjSize;
+ p_wpd->devConf.obj[i].traceId = i;
+ }
+
+ p_wpd->devConf.acc_0g.x = 530;
+ p_wpd->devConf.acc_0g.y = 530;
+ p_wpd->devConf.acc_0g.z = 530;
+ p_wpd->devConf.acc_1g.x = 636;
+ p_wpd->devConf.acc_1g.y = 636;
+ p_wpd->devConf.acc_1g.z = 636;
+ p_wpd->devConf.volume = 0;
+ p_wpd->devConf.motor = 0;
+
+ if (result != WPAD_ERR_OK) {
+ return;
+ }
+
+ if (!p_wpd->oldFw) {
+ for (i = 0; i < 2; i++) {
+ checkSum = 0;
+ index = i * (11);
+ for (j = index; j < index + 10; j++) {
+ checkSum += p_buf[j];
+ }
+ checkSum = (u8)(checkSum + 0x55);
+
+ if (checkSum == p_buf[index + 10]) {
+ DEBUGPrint("Dpd Setting is ok.\n");
+
+ __parse_dpd_data(chan, &p_status, WPAD_DPD_BASIC, p_buf, index + 11);
+
+ obj[0].x = (s16)((s16)((u16)p_buf[index] & 0xFF) |
+ (u16)((u16)(p_buf[index + 2] & 0x30) << 4));
+ obj[0].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(p_buf[index + 1])) & 0xFF) | (u16)(((u16)(p_buf[index + 2] & 0xC0)) << 2)));
+ obj[0].size = p_wpd->dpdDummyObjSize;
+ obj[0].traceId = 0;
+
+ obj[1].x = (s16)((s16)((u16)p_buf[index + 3] & 0xFF) |
+ (u16)((u16)(p_buf[index + 2] & (u8)(0x30 >> 4)) << 8));
+ obj[1].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1 -
+ (s16)((s16)(((u16)(p_buf[index + 4])) & 0xFF) | (u16)(((u16)(p_buf[index + 2] & (u8)(0xC0 >> 4))) << 6)));
+ obj[1].size = p_wpd->dpdDummyObjSize;
+ obj[1].traceId = 1;
+
+ obj[2].x = (s16)((s16)((u16)p_buf[index + 5] & 0xFF) |
+ (u16)((u16)(p_buf[index + 7] & 0x30) << 4));
+ obj[2].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(p_buf[index + 6])) & 0xFF) | (u16)(((u16)(p_buf[index + 7] & 0xC0)) << 2)));
+ obj[2].size = p_wpd->dpdDummyObjSize;
+ obj[2].traceId = 2;
+
+ obj[3].x = (s16)((s16)((u16)p_buf[index + 8] & 0xFF) |
+ (u16)((u16)(p_buf[index + 7] & (u8)(0x30 >> 4)) << 8));
+ obj[3].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1 -
+ (s16)((s16)(((u16)(p_buf[index + 9])) & 0xFF) | (u16)(((u16)(p_buf[index + 7] & (u8)(0xC0 >> 4))) << 6)));
+ obj[3].size = p_wpd->dpdDummyObjSize;
+ obj[3].traceId = 3;
+
+ break;
+ } else {
+ DEBUGPrint("Dpd Setting is broken.\n");
+ }
+ }
+ } else {
+ DEBUGPrint("Old Firmware uses default values because it has no Dpd Setting.\n");
+ }
+
+ for (i = 0; i < 2; i++) {
+ checkSum = 0;
+
+ index = i * (10);
+ if (!p_wpd->oldFw) {
+ index += 22;
+ }
+
+ for (j = index; j < index + 9; j++) {
+ checkSum += p_buf[j];
+ }
+ checkSum = (u8)(checkSum + 0x55);
+ if (checkSum == p_buf[index + 9]) {
+ DEBUGPrint("Acc is ok.\n");
+ p_wpd->devConf.acc_0g.x = (s16)((u16)(((u16)(p_buf[index + 0]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3]) >> 4) & 3));
+ p_wpd->devConf.acc_0g.y = (s16)((u16)(((u16)(p_buf[index + 1]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3]) >> 2) & 3));
+ p_wpd->devConf.acc_0g.z = (s16)((u16)(((u16)(p_buf[index + 2]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3])) & 3));
+ p_wpd->devConf.acc_1g.x = (s16)((u16)(((u16)(p_buf[index + 4]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7]) >> 4) & 3));
+ p_wpd->devConf.acc_1g.y = (s16)((u16)(((u16)(p_buf[index + 5]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7]) >> 2) & 3));
+ p_wpd->devConf.acc_1g.z = (s16)((u16)(((u16)(p_buf[index + 6]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7])) & 3));
+ p_wpd->devConf.volume = (u8)(p_buf[index + 8] & (u8)0x7F);
+ p_wpd->devConf.motor = (u8)(p_buf[index + 8] & (u8)0x80);
+ break;
+ } else {
+ DEBUGPrint("Acc is broken.\n");
+ }
+ }
+ DEBUGPrint("0G: accX = %d, accY = %d, accZ = %d\n", p_wpd->devConf.acc_0g.x, p_wpd->devConf.acc_0g.y, p_wpd->devConf.acc_0g.z);
+ DEBUGPrint("1G: accX = %d, accY = %d, accZ = %d\n", p_wpd->devConf.acc_1g.x, p_wpd->devConf.acc_1g.y, p_wpd->devConf.acc_1g.z);
+ DEBUGPrint("Volume: %d, Motor: %d\n", p_wpd->devConf.volume, p_wpd->devConf.motor);
+}
+
+void getExtConfig(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u8* p_buf = p_wpd->wmReadDataPtr;
+ int i, j, k;
+ int index = -1;
+ int checksum;
+
+ if (result != WPAD_ERR_OK) {
+ p_wpd->devType = WPAD_DEV_NOT_SUPPORTED;
+ } else if (p_wpd->devType == WPAD_DEV_FS || p_wpd->devType == WPAD_DEV_CLASSIC) {
+ WPADiDecode(chan, p_buf, 0x20, 0x20);
+
+ for (i = 0; i < 2; i++) {
+ checksum = 0;
+ k = i * 16;
+ for (j = k; j < k + 14; j++) {
+ checksum += p_buf[j];
+ }
+
+ if (((u8)(checksum + 0x55) == p_buf[k + 14]) && ((u8)(checksum + 0xaa) == p_buf[k + 15])) {
+ index = k;
+ }
+ }
+
+ switch (p_wpd->devType) {
+ case WPAD_DEV_FS:
+ if (index < 0) {
+ DEBUGPrint("check sum error.\n");
+ p_wpd->extConf.fs.acc_0g.x = 512;
+ p_wpd->extConf.fs.acc_0g.y = 512;
+ p_wpd->extConf.fs.acc_0g.z = 512;
+ p_wpd->extConf.fs.acc_1g.x = 716;
+ p_wpd->extConf.fs.acc_1g.y = 716;
+ p_wpd->extConf.fs.acc_1g.z = 716;
+ } else {
+ p_wpd->extConf.fs.acc_0g.x = (s16)((u16)(((u16)(p_buf[index + 0]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3]) >> 4) & 3));
+ p_wpd->extConf.fs.acc_0g.y = (s16)((u16)(((u16)(p_buf[index + 1]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3]) >> 2) & 3));
+ p_wpd->extConf.fs.acc_0g.z = (s16)((u16)(((u16)(p_buf[index + 2]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 3])) & 3));
+ p_wpd->extConf.fs.acc_1g.x = (s16)((u16)(((u16)(p_buf[index + 4]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7]) >> 4) & 3));
+ p_wpd->extConf.fs.acc_1g.y = (s16)((u16)(((u16)(p_buf[index + 5]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7]) >> 2) & 3));
+ p_wpd->extConf.fs.acc_1g.z = (s16)((u16)(((u16)(p_buf[index + 6]) << 2) & 0xFFFC) | (u16)(((u16)(p_buf[index + 7])) & 3));
+ p_wpd->extConf.fs.stick.x_max = (s8)p_buf[index + 8];
+ p_wpd->extConf.fs.stick.x_min = (s8)p_buf[index + 9];
+ p_wpd->extConf.fs.stick.x = (s8)p_buf[index + 10];
+ p_wpd->extConf.fs.stick.y_max = (s8)p_buf[index + 11];
+ p_wpd->extConf.fs.stick.y_min = (s8)p_buf[index + 12];
+ p_wpd->extConf.fs.stick.y = (s8)p_buf[index + 13];
+
+ DEBUGPrint("0G: fsaccX = %d, fsaccY = %d, fsaccZ = %d\n", p_wpd->extConf.fs.acc_0g.x, p_wpd->extConf.fs.acc_0g.y,
+ p_wpd->extConf.fs.acc_0g.z);
+ DEBUGPrint("1G: fsaccX = %d, fsaccY = %d, fsaccZ = %d\n", p_wpd->extConf.fs.acc_1g.x, p_wpd->extConf.fs.acc_1g.y,
+ p_wpd->extConf.fs.acc_1g.z);
+ DEBUGPrint("FS: X = %d, X max = %d, X min = %d\n", p_wpd->extConf.fs.stick.x, p_wpd->extConf.fs.stick.x_max,
+ p_wpd->extConf.fs.stick.x_min);
+ DEBUGPrint("FS: Y = %d, Y max = %d, Y min = %d\n", p_wpd->extConf.fs.stick.y, p_wpd->extConf.fs.stick.y_max,
+ p_wpd->extConf.fs.stick.y_min);
+ }
+ break;
+
+ case WPAD_DEV_CLASSIC:
+ p_wpd->extConf.cl.lstk.x_max = (s8)p_buf[index + 0];
+ p_wpd->extConf.cl.lstk.x_min = (s8)p_buf[index + 1];
+ p_wpd->extConf.cl.lstk.x = (s8)p_buf[index + 2];
+ p_wpd->extConf.cl.lstk.y_max = (s8)p_buf[index + 3];
+ p_wpd->extConf.cl.lstk.y_min = (s8)p_buf[index + 4];
+ p_wpd->extConf.cl.lstk.y = (s8)p_buf[index + 5];
+ p_wpd->extConf.cl.rstk.x_max = (s8)p_buf[index + 6];
+ p_wpd->extConf.cl.rstk.x_min = (s8)p_buf[index + 7];
+ p_wpd->extConf.cl.rstk.x = (s8)p_buf[index + 8];
+ p_wpd->extConf.cl.rstk.y_max = (s8)p_buf[index + 9];
+ p_wpd->extConf.cl.rstk.y_min = (s8)p_buf[index + 10];
+ p_wpd->extConf.cl.rstk.y = (s8)p_buf[index + 11];
+ p_wpd->extConf.cl.triggerL = p_buf[index + 12];
+ p_wpd->extConf.cl.triggerR = p_buf[index + 13];
+
+ DEBUGPrint("CL: X = %d, X max = %d, X min = %d\n", p_wpd->extConf.cl.lstk.x, p_wpd->extConf.cl.lstk.x_max,
+ p_wpd->extConf.cl.lstk.x_min);
+ DEBUGPrint("CL: Y = %d, Y max = %d, Y min = %d\n", p_wpd->extConf.cl.lstk.y, p_wpd->extConf.cl.lstk.y_max,
+ p_wpd->extConf.cl.lstk.y_min);
+ DEBUGPrint("CR: X = %d, X max = %d, X min = %d\n", p_wpd->extConf.cl.rstk.x, p_wpd->extConf.cl.rstk.x_max,
+ p_wpd->extConf.cl.rstk.x_min);
+ DEBUGPrint("CR: Y = %d, Y max = %d, Y min = %d\n", p_wpd->extConf.cl.rstk.y, p_wpd->extConf.cl.rstk.y_max,
+ p_wpd->extConf.cl.rstk.y_min);
+ DEBUGPrint("LR: L = %d, R = %d\n", p_wpd->extConf.cl.triggerL, p_wpd->extConf.cl.triggerR);
+ break;
+ }
+ p_wpd->calibrated = 0;
+ }
+
+ if (p_wpd->cmdBlkCallback) {
+ p_wpd->cmdBlkCallback(chan, p_wpd->devType);
+ p_wpd->cmdBlkCallback = NULL;
+ }
+}
+
+static BOOL isExtEncMain(u8 type) {
+ if (type == WPAD_DEV_FS || type == WPAD_DEV_CLASSIC) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+extern BOOL __OSInIPL;
+
+void getExtType(s32 chan, s32 result) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ WPADCmdQueue* cmdq = &p_wpd->extCmdQueue;
+ u8* p_buf = (u8*)p_wpd->wmReadDataPtr;
+
+ if (result == WPAD_ERR_OK) {
+ WPADiDecode(chan, p_buf, 2, 0xfe);
+
+ p_wpd->devMode = p_buf[0];
+
+ switch (p_buf[1]) {
+ case 0x00:
+ p_wpd->devType = WPAD_DEV_FS;
+ break;
+ case 0x01:
+ p_wpd->devType = WPAD_DEV_CLASSIC;
+ break;
+ default:
+ p_wpd->devType = WPAD_DEV_FUTURE;
+ break;
+ }
+
+ //_devCmpt[chan] = 0;
+ //_devMode[chan] = p_buf[4];
+ if (p_wpd->devType == WPAD_DEV_CLASSIC) {
+ if (p_wpd->devMode < 1 || p_wpd->devMode > 3) {
+ p_wpd->devType = WPAD_DEV_NOT_SUPPORTED;
+ }
+ }
+
+ DEBUGPrint("type : %d\n", p_wpd->devType);
+ DEBUGPrint("mode : %d\n", p_wpd->devMode);
+ } else {
+ p_wpd->devType = WPAD_DEV_NOT_SUPPORTED;
+ p_wpd->devMode = 0;
+ }
+}
+
+void getGameInfo(s32 chan, s32 result, u8 index) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ WPADMEMGameInfo* p_info = p_wpd->wmReadDataPtr;
+ u8* p_buf = p_wpd->wmReadDataPtr;
+ int i;
+ u8 sum = 0;
+
+ if (result == WPAD_ERR_OK) {
+ for (i = 0; i < 47; i++) {
+ sum += p_buf[i];
+ }
+ sum += 0x55;
+
+ if (p_info->checkSum == sum) {
+ memcpy(&p_wpd->gameInfo, p_buf, sizeof(WPADMEMGameInfo));
+ p_wpd->gameInfoErr[index] = WPAD_ERR_OK;
+ } else {
+ p_wpd->gameInfoErr[index] = WPAD_ERR_INVALID;
+ }
+ }
+}
+
+WPADExtensionCallback initExtension(s32 chan, WPADControlBlock* p_wpd) {
+ WPADCmdQueue* cmdQueue = &p_wpd->extCmdQueue;
+ WPADExtensionCallback extCallback = p_wpd->extensionCallback;
+
+ WPADiSendSetReportType(cmdQueue, p_wpd->dataFormat, NULL);
+ WPADiSendWriteDataCmd(cmdQueue, 0xAA, WM_REG_EXTENSION_F0, abortInitExtension);
+
+ WPADiCreateKey(chan);
+ WPADiSendWriteData(cmdQueue, p_wpd->key, 6, WM_REG_EXTENSION_40, abortInitExtension);
+ WPADiSendWriteData(cmdQueue, p_wpd->key + 6, 6, WM_REG_EXTENSION_46, abortInitExtension);
+ WPADiSendWriteData(cmdQueue, p_wpd->key + 12, 4, WM_REG_EXTENSION_4C, abortInitExtension);
+
+ WPADiSendReadData(cmdQueue, p_wpd->wmReadDataBuf, 2, WM_REG_EXTENSION_DEV_MODE, abortInitExtension);
+ WPADiSendReadData(cmdQueue, p_wpd->wmReadDataBuf, 0x20, WM_REG_EXTENSION_CONFIG, extCallback);
+
+ return extCallback;
+}
+
+s32 WPADiHIDParser(u8 chan, u8* data) {
+ int enable;
+ s32 ret = 0;
+
+ if ((data[0] >= 0x20) && (data[0] <= 0x3F)) {
+ enable = OSDisableInterrupts();
+ (*(__a1_input_reports_array[data[0] - 0x20]))(chan, data);
+ OSRestoreInterrupts(enable);
+ WPADiExcludeButton(chan);
+ WPADiCopyOut(chan);
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+void __a1_20_status_report(u8 chan, u8* data) {
+ WPADControlBlock* p_wpd;
+ BOOL enable;
+ BOOL attach;
+ WPADStatus* p_status;
+ WPADExtensionCallback extcb;
+ u8* p_clear;
+ int i;
+ WPADCmdQueue* cmdQueue;
+
+ DEBUGPrint("Received report 20\n");
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+
+ if (!p_wpd->handshakeFinished) {
+ OSRestoreInterrupts(enable);
+ return;
+ }
+
+ p_status = (WPADStatus*)&p_wpd->rxBufs[p_wpd->rxBufIndex];
+ p_clear = (u8*)p_status;
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ attach = p_wpd->info.attach;
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) &
+ HID_WPAD_BUTTON_MASK);
+ p_wpd->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_wpd->info.dpd = (data[HID_IDX_BYTE9] & HID_DPD_MASK) >> 3;
+ p_wpd->info.speaker = (data[HID_IDX_BYTE9] & HID_SPEAKER_MASK) >> 2;
+
+ p_wpd->info.attach = (data[HID_IDX_BYTE9] & HID_ATTACH_MASK) >> 1;
+ p_wpd->info.lowBat = data[HID_IDX_BYTE9] & HID_LOWBAT_MASK;
+ p_wpd->info.led = (u8)((data[HID_IDX_BYTE9] & HID_LED_MASK) >> 4);
+ p_wpd->info.protocol = (u8)((data[HID_IDX_BYTE11] & HID_PRT_MASK) >> 4);
+ p_wpd->info.firmware = (u8)(data[HID_IDX_BYTE11] & HID_FW_MASK);
+
+ if (data[HID_IDX_BYTE12] >= 0x55) {
+ p_wpd->info.battery = WPAD_BATTERY_LEVEL_MAX;
+ } else if (data[HID_IDX_BYTE12] >= 0x44) {
+ p_wpd->info.battery = WPAD_BATTERY_LEVEL_HIGH;
+ } else if (data[HID_IDX_BYTE12] >= 0x33) {
+ p_wpd->info.battery = WPAD_BATTERY_LEVEL_MEDIUM;
+ } else if (data[HID_IDX_BYTE12] >= 0x3) {
+ p_wpd->info.battery = WPAD_BATTERY_LEVEL_LOW;
+ } else {
+ p_wpd->info.battery = WPAD_BATTERY_LEVEL_CRITICAL;
+ }
+
+ if (p_wpd->info.attach) {
+ if (!attach) {
+ DEBUGPrint("initialize attachment\n");
+
+ extcb = initExtension(chan, p_wpd);
+
+ cmdQueue = &p_wpd->extCmdQueue;
+
+ p_wpd->calibrated = 0;
+ p_wpd->devType = WPAD_DEV_INITIALIZING;
+ p_wpd->devMode = 0;
+
+ if (extcb) {
+ extcb(chan, WPAD_DEV_INITIALIZING);
+ }
+ } else {
+ DEBUGPrint("already initialized\n");
+ }
+ } else {
+ p_wpd->devType = WPAD_DEV_CORE;
+ p_wpd->devMode = 0;
+
+ if (attach) {
+ WPADiClearQueue(&p_wpd->extCmdQueue);
+ WPADiSendSetReportType(&p_wpd->stdCmdQueue, p_wpd->dataFormat, NULL);
+
+ if (p_wpd->extensionCallback) {
+ p_wpd->extensionCallback(chan, WPAD_DEV_CORE);
+ }
+ } else {
+ DEBUGPrint("already disconnected\n");
+ }
+ }
+
+ if (p_wpd->infoOut) {
+ memcpy(p_wpd->infoOut, &p_wpd->info, sizeof(WPADInfo));
+ p_wpd->infoOut = NULL;
+ }
+
+ if (p_wpd->cmdBlkCallback && p_wpd->statusReqBusy) {
+ p_wpd->cmdBlkCallback(chan, WPAD_ERR_OK);
+ p_wpd->cmdBlkCallback = NULL;
+ }
+
+ p_status->err = WPAD_ERR_BUSY;
+ p_status->dev = p_wpd->devType;
+ p_wpd->statusReqBusy = 0;
+ p_wpd->rxBufIndex = (u8)((p_wpd->rxBufIndex) ? 0 : 1);
+
+ OSRestoreInterrupts(enable);
+}
+
+void __a1_21_user_data(u8 chan, u8* data) {
+ WPADControlBlock* p_wpd;
+ BOOL enable;
+ WPADStatus* p_status;
+ u8* p_clear;
+ u16 addr;
+ u16 base;
+ u16 i2c;
+ u8 err;
+ u8 len;
+ s16 offset;
+ int i;
+ s32 status;
+
+ enable = OSDisableInterrupts();
+ p_wpd = _wpdcb[chan];
+ p_status = (WPADStatus*)(p_wpd->rxBufs + p_wpd->rxBufIndex);
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) &
+ HID_WPAD_BUTTON_MASK);
+
+ err = (u8)(data[HID_IDX_BYTE9] & 0x0f);
+ len = (u8)(((u8)(data[HID_IDX_BYTE9] >> 4) & 0x0f) + 1);
+ addr = (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE10]) << 8) & (u16)0xFF00) | (u16)((u16)(data[HID_IDX_BYTE11]) & (u16)0xFF));
+
+ if (err != 0) {
+ DEBUGPrint("read error happens!\n");
+ p_wpd->wmReadErr = -1;
+
+ if (p_wpd->cmdBlkCallback) {
+ p_wpd->cmdBlkCallback(chan, WPAD_ERR_TRANSFER);
+ p_wpd->cmdBlkCallback = NULL;
+ }
+ p_wpd->status = WPAD_ERR_OK;
+ }
+
+ base = (u16)(p_wpd->wmReadAddr & 0xFFFF);
+ i2c = (u16)((p_wpd->wmReadAddr & 0xFFFF0000) >> 16);
+ offset = (s16)(addr - base);
+
+ if (addr >= base && addr <= base + p_wpd->wmReadLength) {
+ memcpy((u8*)p_wpd->wmReadDataPtr + offset, data + HID_IDX_BYTE12, len);
+
+ if (base + p_wpd->wmReadLength == addr + len) {
+ DEBUGPrint("base addr: %08x\n", p_wpd->wmReadAddr);
+ DEBUGPrint("length : %d\n", p_wpd->wmReadLength);
+ status = p_wpd->wmReadErr < 0 ? WPAD_CETRANSFER : WPAD_CESUCCESS;
+
+ if ((p_wpd->wmReadAddr == 0 && p_wpd->oldFw == FALSE) ||
+ (p_wpd->wmReadAddr == WM_ADDR_MEM_176C && p_wpd->oldFw == TRUE)) {
+ getDevConfig(chan, status, p_status, data);
+ }
+ if (p_wpd->wmReadAddr == WM_REG_EXTENSION_CONFIG) {
+ getExtConfig(chan, status);
+ }
+ if (p_wpd->wmReadAddr == WM_REG_EXTENSION_DEV_MODE) {
+ getExtType(chan, status);
+ }
+ if (p_wpd->wmReadAddr == 0x2A) {
+ getGameInfo(chan, status, 0);
+ }
+ if (p_wpd->wmReadAddr == 0x2A + sizeof(WPADMEMGameInfo)) {
+ getGameInfo(chan, status, 1);
+ }
+
+ if (p_wpd->cmdBlkCallback) {
+ p_wpd->cmdBlkCallback(chan, status);
+ p_wpd->cmdBlkCallback = NULL;
+ }
+ p_wpd->status = WPAD_ERR_OK;
+ }
+ } else {
+ DEBUGPrint("received data is out of range!\n");
+ }
+
+ p_status->err = WPAD_ERR_BUSY;
+ p_status->dev = p_wpd->devType;
+
+ p_wpd->rxBufIndex = (u8)((p_wpd->rxBufIndex) ? 0 : 1);
+
+ OSRestoreInterrupts(enable);
+}
+
+void __a1_22_ack(u8 chan, u8* data) {
+ WPADControlBlock* p_wpd = _wpdcb[chan];
+ u8 type;
+ u8 err;
+ BOOL enable;
+ WPADStatus* p_status;
+ u8* p_clear;
+ s32 status;
+ int i;
+
+ enable = OSDisableInterrupts();
+
+ DEBUGPrint("Received ack!\n");
+
+ p_wpd = _wpdcb[chan];
+ p_status = (WPADStatus*)(p_wpd->rxBufs + p_wpd->rxBufIndex);
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ type = data[HID_IDX_BYTE9];
+ err = data[HID_IDX_BYTE10];
+
+ DEBUGPrint("ack --> report ID = %02x, error code = %d\n", type, err);
+
+ status = err == 0 ? WPAD_CESUCCESS : WPAD_CETRANSFER;
+ p_status->err = WPAD_ERR_BUSY;
+ p_status->dev = p_wpd->devType;
+
+ if (err != 0) {
+ DEBUGPrint("ack error --> report ID = %d, error code = %d\n", type, err);
+ }
+
+ if (p_wpd->lastReportId == type) {
+ if (p_wpd->cmdBlkCallback) {
+ p_wpd->cmdBlkCallback(chan, status);
+ p_wpd->cmdBlkCallback = NULL;
+ }
+ p_wpd->status = WPAD_ERR_OK;
+ } else {
+ DEBUGPrint("invalid ack!\n");
+ }
+ p_wpd->rxBufIndex = (u8)((p_wpd->rxBufIndex) ? 0 : 1);
+
+ OSRestoreInterrupts(enable);
+}
+
+void __a1_30_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ u8* p_clear;
+
+ int old;
+ int i;
+
+ old = OSDisableInterrupts();
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)data[HID_IDX_BYTE7] & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) &
+ HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN) {
+ p_status->err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+
+void __a1_31_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ u8* p_clear;
+ int old, i;
+
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)data[HID_IDX_BYTE7] & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) &
+ HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC) {
+ p_status->err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_status->accX = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE9] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE7] >> 5) & (s16)0x0003)) -
+ p_cb->devConf.acc_0g.x);
+ p_status->accY = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE10] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE8] >> 4) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.y);
+ p_status->accZ = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE11] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE8] >> 5) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.z);
+ old = OSDisableInterrupts();
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+
+void __a1_32_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ WPADFSStatus* p_fsStat;
+ WPADCLStatus* p_clStat;
+ u8* p_clear;
+ int old, i;
+ s16 x, y;
+ old = OSDisableInterrupts();
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_FS_BTN || p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN) {
+ p_status->err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+
+ memcpy(checkBuffer, data + HID_IDX_BYTE9, 8);
+ WPADiDecode(chan, data + HID_IDX_BYTE9, 8, 0);
+
+ if (p_cb->info.attach) {
+ if (p_cb->devType == WPAD_DEV_FS) {
+ p_fsStat = (WPADFSStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_fsStat->fsStickX = (s8)(data[HID_IDX_BYTE9]);
+ p_fsStat->fsStickY = (s8)(data[HID_IDX_BYTE10]);
+ p_fsStat->fsAccX =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE14] >> 2) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.x);
+ p_fsStat->fsAccY =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE14] >> 4) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.y);
+ p_fsStat->fsAccZ =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE13]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE14] >> 6) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.z);
+
+ p_fsStat->base.button |= (u16)(((u16)(~data[HID_IDX_BYTE14]) << 13) & (u16)0x6000);
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.fs.stick.x = p_fsStat->fsStickX;
+ p_cb->extConf.fs.stick.y = p_fsStat->fsStickY;
+ }
+
+ x = (s16)((u8)p_fsStat->fsStickX - (u8)p_cb->extConf.fs.stick.x);
+ y = (s16)((u8)p_fsStat->fsStickY - (u8)p_cb->extConf.fs.stick.y);
+
+ if (x < -128) {
+ p_fsStat->fsStickX = -128;
+ } else if (x > 127) {
+ p_fsStat->fsStickX = 127;
+ } else {
+ p_fsStat->fsStickX = (s8)x;
+ }
+
+ if (y < -128) {
+ p_fsStat->fsStickY = -128;
+ } else if (y > 127) {
+ p_fsStat->fsStickY = 127;
+ } else {
+ p_fsStat->fsStickY = (s8)y;
+ }
+ } else if (p_cb->devType == WPAD_DEV_CLASSIC) {
+ switch (p_cb->devMode) {
+ case 1:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) & (s16)0x003F) << 4));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE10]) & (s16)0x003F) << 4));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) >> 3) & (s16)0x0018) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE10]) >> 5) & (s16)0x0006) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE11]) >> 7) & (s16)0x0001))
+ << 5) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) & (s16)0x001F) << 5) - (s16)(1024 / 2));
+ p_clStat->clTriggerL =
+ (u8)((u8)((u8)((u8)(data[HID_IDX_BYTE11] >> 2) & (u8)0x18) | (u8)((u8)(data[HID_IDX_BYTE12] >> 5) & (u8)0x07)) << 3);
+ p_clStat->clTriggerR = (u8)((u8)(data[HID_IDX_BYTE12] & (u8)0x1F) << 3);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE13]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE14]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+
+ case 2:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE13])) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE10]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE13]) >> 2) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE13]) >> 4) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE13]) >> 6) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE14]);
+ p_clStat->clTriggerR = (u8)(data[HID_IDX_BYTE15]);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE16]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE17]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+
+ case 3:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE10]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE13]);
+ p_clStat->clTriggerR = (u8)(data[HID_IDX_BYTE14]);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE15]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE16]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+ }
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.cl.lstk.x = p_clStat->clLStickX;
+ p_cb->extConf.cl.lstk.y = p_clStat->clLStickY;
+ p_cb->extConf.cl.rstk.x = p_clStat->clRStickX;
+ p_cb->extConf.cl.rstk.y = p_clStat->clRStickY;
+ p_cb->extConf.cl.triggerL = p_clStat->clTriggerL;
+ p_cb->extConf.cl.triggerR = p_clStat->clTriggerR;
+ }
+
+ x = (s16)(p_clStat->clLStickX - p_cb->extConf.cl.lstk.x);
+ y = (s16)(p_clStat->clLStickY - p_cb->extConf.cl.lstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clLStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clLStickX = 0x3FF;
+ } else {
+ p_clStat->clLStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clLStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clLStickY = 0x3FF;
+ } else {
+ p_clStat->clLStickY = y;
+ }
+
+ x = (s16)(p_clStat->clRStickX - p_cb->extConf.cl.rstk.x);
+ y = (s16)(p_clStat->clRStickY - p_cb->extConf.cl.rstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clRStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clRStickX = 0x3FF;
+ } else {
+ p_clStat->clRStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clRStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clRStickY = 0x3FF;
+ } else {
+ p_clStat->clRStickY = y;
+ }
+
+ x = (s16)((u8)p_clStat->clTriggerL - (u8)p_cb->extConf.cl.triggerL);
+ y = (s16)((u8)p_clStat->clTriggerR - (u8)p_cb->extConf.cl.triggerR);
+
+ if (x < 0) {
+ p_clStat->clTriggerL = 0;
+ } else {
+ p_clStat->clTriggerL = p_clStat->clTriggerL = (u8)x;
+ }
+
+ if (y < 0) {
+ p_clStat->clTriggerR = 0;
+ } else {
+ p_clStat->clTriggerR = p_clStat->clTriggerR = (u8)y;
+ }
+ }
+
+ if (!memcmp(checkBuffer, checkInvalidData, 7)) {
+ if (p_status->err == WPAD_ERR_OK) {
+ p_status->err = WPAD_ERR_CORRUPTED;
+ }
+ }
+ }
+
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+
+void __a1_33_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ u8* p_clear;
+ int old, i;
+
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clear = (u8*)(p_status);
+
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC_DPD) {
+ p_status->err = WPAD_ERR_OK;
+ } else {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_status->accX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE7] >> 5)) & (s16)0x0003))) -
+ (s16)(p_cb->devConf.acc_0g.x));
+ p_status->accY = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE10]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE8] >> 4)) & (s16)0x0002))) -
+ (s16)(p_cb->devConf.acc_0g.y));
+ p_status->accZ = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE8] >> 5)) & (s16)0x0002))) -
+ (s16)(p_cb->devConf.acc_0g.z));
+
+ __parse_dpd_data(chan, &p_status, WPAD_DPD_STANDARD, data, 0);
+
+ old = OSDisableInterrupts();
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+
+void __a1_34_data_type(u8 chan, u8* data) {
+ // empty function
+}
+
+void __a1_35_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ WPADFSStatus* p_fsStat;
+ WPADCLStatus* p_clStat;
+ u8* p_clear;
+ int old, i;
+ s16 x, y;
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC || p_cb->dataFormat == WPAD_FMT_FS_BTN ||
+ p_cb->dataFormat == WPAD_FMT_FS_BTN_ACC || p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN || p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN_ACC) {
+ p_status->err = p_cb->status;
+ } else if (p_cb->status != 0) {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_status->accX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE7] >> 5)) & (s16)0x0003))) -
+ (s16)(p_cb->devConf.acc_0g.x));
+ p_status->accY = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE10]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE8] >> 4)) & (s16)0x0002))) -
+ (s16)(p_cb->devConf.acc_0g.y));
+ p_status->accZ = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE11]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE8] >> 5)) & (s16)0x0002))) -
+ (s16)(p_cb->devConf.acc_0g.z));
+
+ memcpy(checkBuffer, data + HID_IDX_BYTE12, 16);
+ WPADiDecode(chan, data + HID_IDX_BYTE12, 16, 0);
+
+ if (p_cb->info.attach) {
+ if (p_cb->devType == WPAD_DEV_FS) {
+ p_fsStat = (WPADFSStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_fsStat->fsStickX = (s8)(data[HID_IDX_BYTE12]);
+ p_fsStat->fsStickY = (s8)(data[HID_IDX_BYTE13]);
+ p_fsStat->fsAccX =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE14]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE17] >> 2) & (s16)(0x0003))) -
+ (s16)(p_cb->extConf.fs.acc_0g.x));
+ p_fsStat->fsAccY =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE15]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE17] >> 4) & (s16)(0x0003))) -
+ (s16)(p_cb->extConf.fs.acc_0g.y));
+ p_fsStat->fsAccZ =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE16]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE17] >> 6) & (s16)(0x0003))) -
+ (s16)(p_cb->extConf.fs.acc_0g.z));
+
+ p_fsStat->base.button |= (u16)(((u16)(~data[HID_IDX_BYTE17]) << 13) & (u16)0x6000);
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.fs.stick.x = p_fsStat->fsStickX;
+ p_cb->extConf.fs.stick.y = p_fsStat->fsStickY;
+ }
+
+ x = (s16)((u8)p_fsStat->fsStickX - (u8)p_cb->extConf.fs.stick.x);
+ y = (s16)((u8)p_fsStat->fsStickY - (u8)p_cb->extConf.fs.stick.y);
+
+ if (x < -128) {
+ p_fsStat->fsStickX = -128;
+ } else if (x > 127) {
+ p_fsStat->fsStickX = 127;
+ } else {
+ p_fsStat->fsStickX = (s8)x;
+ }
+
+ if (y < -128) {
+ p_fsStat->fsStickY = -128;
+ } else if (y > 127) {
+ p_fsStat->fsStickY = 127;
+ } else {
+ p_fsStat->fsStickY = (s8)y;
+ }
+ } else if (p_cb->devType == WPAD_DEV_CLASSIC) {
+ switch (p_cb->devMode) {
+ case 1:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) & (s16)0x003F) << 4) - (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE13]) & (s16)0x003F) << 4) - (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) >> 3) & (s16)0x0018) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE13]) >> 5) & (s16)0x0006) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE14]) >> 7) & (s16)0x0001))
+ << 5) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE14]) & (s16)0x001F) << 5) - (s16)(1024 / 2));
+ p_clStat->clTriggerL =
+ (u8)((u8)((u8)((u8)(data[HID_IDX_BYTE14] >> 2) & (u8)0x18) | (u8)((u8)(data[HID_IDX_BYTE15] >> 5) & (u8)0x07)) << 3);
+ p_clStat->clTriggerR = (u8)((u8)((u8)(data[HID_IDX_BYTE15]) & (u8)0x1F) << 3);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE16]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE17]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+
+ case 2:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE16])) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE13]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE16]) >> 2) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE14]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE16]) >> 4) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE15]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE16]) >> 6) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE17]);
+ p_clStat->clTriggerR = (u8)(data[HID_IDX_BYTE18]);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE19]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE20]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+
+ case 3:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE12]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE13]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE14]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE15]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE16]);
+ p_clStat->clTriggerR = (u8)(data[HID_IDX_BYTE17]);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE18]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE19]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+ }
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.cl.lstk.x = p_clStat->clLStickX;
+ p_cb->extConf.cl.lstk.y = p_clStat->clLStickY;
+ p_cb->extConf.cl.rstk.x = p_clStat->clRStickX;
+ p_cb->extConf.cl.rstk.y = p_clStat->clRStickY;
+ p_cb->extConf.cl.triggerL = p_clStat->clTriggerL;
+ p_cb->extConf.cl.triggerR = p_clStat->clTriggerR;
+ }
+
+ x = (s16)(p_clStat->clLStickX - p_cb->extConf.cl.lstk.x);
+ y = (s16)(p_clStat->clLStickY - p_cb->extConf.cl.lstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clLStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clLStickX = 0x3FF;
+ } else {
+ p_clStat->clLStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clLStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clLStickY = 0x3FF;
+ } else {
+ p_clStat->clLStickY = y;
+ }
+
+ x = (s16)(p_clStat->clRStickX - p_cb->extConf.cl.rstk.x);
+ y = (s16)(p_clStat->clRStickY - p_cb->extConf.cl.rstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clRStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clRStickX = 0x3FF;
+ } else {
+ p_clStat->clRStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clRStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clRStickY = 0x3FF;
+ } else {
+ p_clStat->clRStickY = y;
+ }
+
+ x = (s16)(p_clStat->clTriggerL - p_cb->extConf.cl.triggerL);
+ y = (s16)(p_clStat->clTriggerR - p_cb->extConf.cl.triggerR);
+
+ if (x < 0) {
+ p_clStat->clTriggerL = 0;
+ } else {
+ p_clStat->clTriggerL = p_clStat->clTriggerL = (u8)x;
+ }
+
+ if (y < 0) {
+ p_clStat->clTriggerR = 0;
+ } else {
+ p_clStat->clTriggerR = p_clStat->clTriggerR = (u8)y;
+ }
+ }
+
+ if (!memcmp(checkBuffer, checkInvalidData, 16)) {
+ if (p_status->err == WPAD_ERR_OK) {
+ p_status->err = WPAD_ERR_CORRUPTED;
+ }
+ }
+ }
+
+ old = OSDisableInterrupts();
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+
+void __a1_36_data_type(u8 chan, u8* data) {
+ // empty function
+}
+
+void __a1_37_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatus* p_status;
+ WPADFSStatus* p_fsStat;
+ WPADCLStatus* p_clStat;
+ u8* p_clear;
+ int old, i;
+ s16 x, y;
+ s16 temp_r0;
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clear = (u8*)(p_status);
+
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+
+ p_status->button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC_DPD ||
+ p_cb->dataFormat == WPAD_FMT_FS_BTN || p_cb->dataFormat == WPAD_FMT_FS_BTN_ACC || p_cb->dataFormat == WPAD_FMT_FS_BTN_ACC_DPD ||
+ p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN || p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN_ACC || p_cb->dataFormat == WPAD_FMT_CLASSIC_BTN_ACC_DPD) {
+ p_status->err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->err = WPAD_ERR_INVALID;
+ }
+
+ p_status->dev = p_cb->devType;
+ p_cb->info.nearempty = (u8)((data[HID_IDX_BYTE7] & HID_NEAREMPTY_MASK) >> 7);
+ p_status->accX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE9]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((u16)(data[HID_IDX_BYTE7] >> 5)) & (s16)0x0003))) -
+ p_cb->devConf.acc_0g.x);
+ p_status->accY = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE10] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE8] >> 4) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.y);
+ p_status->accZ = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE11] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE8] >> 5) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.z);
+
+ __parse_dpd_data(chan, &p_status, WPAD_DPD_STANDARD, data, 0);
+
+ memcpy(checkBuffer, data + HID_IDX_BYTE22, 6);
+ WPADiDecode(chan, data + HID_IDX_BYTE22, 6, 0);
+
+ if (p_cb->info.attach) {
+ if (p_cb->devType == WPAD_DEV_FS) {
+ p_fsStat = (WPADFSStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_fsStat->fsStickX = (s8)(data[HID_IDX_BYTE22]);
+ p_fsStat->fsStickY = (s8)(data[HID_IDX_BYTE23]);
+ p_fsStat->fsAccX =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE24]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE27] >> 2) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.x);
+ p_fsStat->fsAccY =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE25]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE27] >> 4) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.y);
+ p_fsStat->fsAccZ =
+ (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE26]) << 2) & (s16)0xFFFC) | (s16)((s16)(data[HID_IDX_BYTE27] >> 6) & (s16)(0x0003))) -
+ p_cb->extConf.fs.acc_0g.z);
+
+ p_fsStat->base.button |= (u16)(((u16)(~data[HID_IDX_BYTE27]) << 13) & (u16)0x6000);
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.fs.stick.x = p_fsStat->fsStickX;
+ p_cb->extConf.fs.stick.y = p_fsStat->fsStickY;
+ }
+
+ x = (s16)((u8)p_fsStat->fsStickX - (u8)p_cb->extConf.fs.stick.x);
+ y = (s16)((u8)p_fsStat->fsStickY - (u8)p_cb->extConf.fs.stick.y);
+
+ if (x < -128) {
+ p_fsStat->fsStickX = -128;
+ } else if (x > 127) {
+ p_fsStat->fsStickX = 127;
+ } else {
+ p_fsStat->fsStickX = (s8)x;
+ }
+
+ if (y < -128) {
+ p_fsStat->fsStickY = -128;
+ } else if (y > 127) {
+ p_fsStat->fsStickY = 127;
+ } else {
+ p_fsStat->fsStickY = (s8)y;
+ }
+ } else if (p_cb->devType == WPAD_DEV_CLASSIC) {
+ switch (p_cb->devMode) {
+ case 1:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE22]) & (s16)0x003F) << 4) - (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE23]) & (s16)0x003F) << 4) - (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE22]) >> 3) & (s16)0x0018) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE23]) >> 5) & (s16)0x0006) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE24]) >> 7) & (s16)0x0001))
+ << 5) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE24]) & (s16)0x001F) << 5) - (s16)(1024 / 2));
+ p_clStat->clTriggerL =
+ (u8)((u8)((u8)((u8)(data[HID_IDX_BYTE24] >> 2) & (u8)0x18) | (u8)((u8)(data[HID_IDX_BYTE25] >> 5) & (u8)0x07)) << 3);
+ p_clStat->clTriggerR = (u8)((u8)((u8)(data[HID_IDX_BYTE25]) & (u8)0x1F) << 3);
+
+ p_clStat->clButton =
+ (u16)((u16)((u16)((u16)(data[HID_IDX_BYTE26]) << 8) & (u16)0xFF00 | (u16)(data[HID_IDX_BYTE27]) & (u16)0xFF) ^ 0xFFFF);
+ break;
+
+ case 2:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE22]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE26])) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE23]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE26]) >> 2) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE24]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE26]) >> 4) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)((s16)(data[HID_IDX_BYTE25]) << 2) & (s16)0xFFFC) |
+ (s16)((s16)((s16)(data[HID_IDX_BYTE26]) >> 6) & (s16)0x0003)) -
+ (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE27]);
+ p_clStat->clTriggerR = (u8)0;
+
+ p_clStat->clButton = (u16)0;
+ break;
+
+ case 3:
+ p_clStat = (WPADCLStatus*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ p_clStat->clLStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE22]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickX = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE23]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clLStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE24]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clRStickY = (s16)((s16)((s16)((s16)(data[HID_IDX_BYTE25]) & (s16)0xFF) << 2) - (s16)(1024 / 2));
+ p_clStat->clTriggerL = (u8)(data[HID_IDX_BYTE26]);
+ p_clStat->clTriggerR = (u8)(data[HID_IDX_BYTE27]);
+
+ p_clStat->clButton = (u16)0;
+ break;
+ }
+
+ if (!p_cb->calibrated) {
+ p_cb->calibrated = 1;
+ p_cb->extConf.cl.lstk.x = p_clStat->clLStickX;
+ p_cb->extConf.cl.lstk.y = p_clStat->clLStickY;
+ p_cb->extConf.cl.rstk.x = p_clStat->clRStickX;
+ p_cb->extConf.cl.rstk.y = p_clStat->clRStickY;
+ p_cb->extConf.cl.triggerL = p_clStat->clTriggerL;
+ p_cb->extConf.cl.triggerR = p_clStat->clTriggerR;
+ }
+
+ x = (s16)(p_clStat->clLStickX - p_cb->extConf.cl.lstk.x);
+ y = (s16)(p_clStat->clLStickY - p_cb->extConf.cl.lstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clLStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clLStickX = 0x3FF;
+ } else {
+ p_clStat->clLStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clLStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clLStickY = 0x3FF;
+ } else {
+ p_clStat->clLStickY = y;
+ }
+
+ x = (s16)(p_clStat->clRStickX - p_cb->extConf.cl.rstk.x);
+ y = (s16)(p_clStat->clRStickY - p_cb->extConf.cl.rstk.y);
+
+ if (x < -0x400) {
+ p_clStat->clRStickX = -0x400;
+ } else if (x > 0x3FF) {
+ p_clStat->clRStickX = 0x3FF;
+ } else {
+ p_clStat->clRStickX = x;
+ }
+
+ if (y < -0x400) {
+ p_clStat->clRStickY = -0x400;
+ } else if (y > 0x3FF) {
+ p_clStat->clRStickY = 0x3FF;
+ } else {
+ p_clStat->clRStickY = y;
+ }
+
+ x = (s16)(p_clStat->clTriggerL - p_cb->extConf.cl.triggerL);
+ y = (s16)(p_clStat->clTriggerR - p_cb->extConf.cl.triggerR);
+
+ if (x < 0) {
+ p_clStat->clTriggerL = 0;
+ } else {
+ p_clStat->clTriggerL = p_clStat->clTriggerL = (u8)x;
+ }
+
+ if (y < 0) {
+ p_clStat->clTriggerR = 0;
+ } else {
+ p_clStat->clTriggerR = p_clStat->clTriggerR = (u8)y;
+ }
+ }
+
+ if (!memcmp(checkBuffer, checkInvalidData, 6)) {
+ if (p_status->err == WPAD_ERR_OK) {
+ p_status->err = WPAD_ERR_CORRUPTED;
+ }
+ }
+ }
+
+ old = OSDisableInterrupts();
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ OSRestoreInterrupts(old);
+}
+void __a1_3d_data_type(u8 chan, u8* data) {}
+
+u8 _recv_3e[WPAD_MAX_CONTROLLERS] = {0, 0, 0, 0};
+u8 _recv_3f[WPAD_MAX_CONTROLLERS] = {0, 0, 0, 0};
+
+void __a1_3e_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatusEx* p_status;
+ u8* p_clear;
+ int old, i;
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatusEx*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ if (_recv_3e[chan] == 0 && _recv_3f[chan] == 0) {
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+ }
+
+ p_status->base.button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) & (u16)HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN ||
+ p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC ||
+ p_cb->dataFormat == WPAD_FMT_BTN_ACC_DPD_EXTENDED) {
+ p_status->base.err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->base.err = WPAD_ERR_INVALID;
+ }
+ p_status->base.dev = p_cb->devType;
+ p_cb->info.nearempty = 0;
+ p_status->base.accX = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE9] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE7] >> 6) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.x);
+ p_status->base.accZ |= (s16)((s16)((s16)((s16)data[HID_IDX_BYTE8] << 3) & (s16)0xFF00) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE7] << 1) & (s16)0x00C0));
+
+ p_status->base.obj[0].x = (s16)((s16)((u16)data[HID_IDX_BYTE10] & 0xFF) |
+ (u16)((u16)(data[HID_IDX_BYTE12] & 0x30) << 4));
+ p_status->base.obj[0].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(data[HID_IDX_BYTE11])) & 0xFF) | (u16)(((u16)(data[HID_IDX_BYTE12] & 0xC0)) << 2)));
+ p_status->exp[0].pixel = (u16)(((s16)((s16)(((u16)(data[HID_IDX_BYTE17]) << 8) & 0xFF00) | (u16)(data[HID_IDX_BYTE18] & 0xFF))) * 64);
+ p_status->exp[0].radius = (s8)((data[HID_IDX_BYTE12] & 0x0f));
+ p_status->exp[0].range_x1 = (s16)(((s8)(data[HID_IDX_BYTE13]) == -1) ? 0 : data[HID_IDX_BYTE13]);
+ p_status->exp[0].range_y1 = (s16)(((s8)(data[HID_IDX_BYTE14]) == -1) ? 0 : data[HID_IDX_BYTE14]);
+ p_status->exp[0].range_x2 = (s16)(((s8)(data[HID_IDX_BYTE15]) == -1) ? 0 : data[HID_IDX_BYTE15]);
+ p_status->exp[0].range_y2 = (s16)(((s8)(data[HID_IDX_BYTE16]) == -1) ? 0 : data[HID_IDX_BYTE16]);
+ p_status->exp[0].range_x1 = (s16)(p_status->exp[0].range_x1 * 8);
+ p_status->exp[0].range_y1 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[0].range_y1 * 8));
+ p_status->exp[0].range_x2 = (s16)(p_status->exp[0].range_x2 * 8);
+ p_status->exp[0].range_y2 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[0].range_y2 * 8));
+ p_status->base.obj[0].size = (u16)((f32)p_status->exp[0].radius * (f32)p_status->exp[0].radius * PI);
+ if (p_status->base.obj[0].size == 0 || p_status->base.obj[0].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) ||
+ p_status->base.obj[0].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1) || p_status->exp[0].radius == 0xf) {
+ p_status->base.obj[0].x = (s16)0;
+ p_status->base.obj[0].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ p_status->base.obj[0].size = 0;
+ p_status->exp[0].pixel = 0;
+ p_status->exp[0].radius = 0;
+ }
+ p_status->base.obj[0].traceId = 0;
+
+ p_status->base.obj[1].x = (s16)((s16)((u16)data[HID_IDX_BYTE19] & 0xFF) |
+ (u16)((u16)(data[HID_IDX_BYTE21] & 0x30) << 4));
+ p_status->base.obj[1].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(data[HID_IDX_BYTE20])) & 0xFF) | (u16)(((u16)(data[HID_IDX_BYTE21] & 0xC0)) << 2)));
+ p_status->exp[1].pixel = (u16)(((s16)((s16)(((u16)(data[HID_IDX_BYTE26]) << 8) & 0xFF00) | (u16)(data[HID_IDX_BYTE27] & 0xFF))) * 64);
+ p_status->exp[1].radius = (s8)((data[HID_IDX_BYTE21] & 0x0f));
+ p_status->exp[1].range_x1 = (s16)(((s8)(data[HID_IDX_BYTE22]) == -1) ? 0 : data[HID_IDX_BYTE22]);
+ p_status->exp[1].range_y1 = (s16)(((s8)(data[HID_IDX_BYTE23]) == -1) ? 0 : data[HID_IDX_BYTE23]);
+ p_status->exp[1].range_x2 = (s16)(((s8)(data[HID_IDX_BYTE24]) == -1) ? 0 : data[HID_IDX_BYTE24]);
+ p_status->exp[1].range_y2 = (s16)(((s8)(data[HID_IDX_BYTE25]) == -1) ? 0 : data[HID_IDX_BYTE25]);
+ p_status->exp[1].range_x1 = (s16)(p_status->exp[1].range_x1 * 8);
+ p_status->exp[1].range_y1 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[1].range_y1 * 8));
+ p_status->exp[1].range_x2 = (s16)(p_status->exp[1].range_x2 * 8);
+ p_status->exp[1].range_y2 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[1].range_y2 * 8));
+ p_status->base.obj[1].size = (u16)((f32)p_status->exp[1].radius * (f32)p_status->exp[1].radius * PI);
+ if (p_status->base.obj[1].size == 0 || p_status->base.obj[1].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) ||
+ p_status->base.obj[1].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1) || p_status->exp[1].radius == 0xf) {
+ p_status->base.obj[1].x = (s16)0;
+ p_status->base.obj[1].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ p_status->base.obj[1].size = 0;
+ p_status->exp[1].pixel = 0;
+ p_status->exp[1].radius = 0;
+ }
+ p_status->base.obj[1].traceId = 1;
+
+ old = OSDisableInterrupts();
+ _recv_3e[chan] = 1;
+ if (_recv_3e[chan] && _recv_3f[chan]) {
+ p_status->base.accZ -= (s16)(p_cb->devConf.acc_0g.z);
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ _recv_3e[chan] = _recv_3f[chan] = 0;
+ }
+ OSRestoreInterrupts(old);
+}
+
+void __a1_3f_data_type(u8 chan, u8* data) {
+ WPADControlBlock* p_cb;
+ WPADStatusEx* p_status;
+ u8* p_clear;
+ int old, i;
+ p_cb = _wpdcb[chan];
+ p_status = (WPADStatusEx*)&p_cb->rxBufs[p_cb->rxBufIndex];
+
+ if (_recv_3e[chan] == 0 && _recv_3f[chan] == 0) {
+ p_clear = (u8*)(p_status);
+ for (i = 0; i < WPAD_RX_DATASIZE; i++) {
+ p_clear[i] = 0;
+ }
+ }
+
+ p_status->base.button =
+ (u16)((u16)(((u16)((u16)(data[HID_IDX_BYTE7]) & 0xFF) | (u16)((u16)(data[HID_IDX_BYTE8] << 8) & 0xFF00))) &
+ HID_WPAD_BUTTON_MASK);
+
+ if (p_cb->dataFormat == WPAD_FMT_CORE_BTN || p_cb->dataFormat == WPAD_FMT_CORE_BTN_ACC || p_cb->dataFormat == WPAD_FMT_BTN_ACC_DPD_EXTENDED) {
+ p_status->base.err = p_cb->status;
+ } else if (p_cb->status == 0) {
+ p_status->base.err = WPAD_ERR_INVALID;
+ }
+ p_status->base.dev = p_cb->devType;
+ p_cb->info.nearempty = 0;
+ p_status->base.accY = (s16)((s16)((s16)((s16)((s16)data[HID_IDX_BYTE9] << 2) & (s16)0xFFFC) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE7] >> 6) & (s16)0x0002)) -
+ p_cb->devConf.acc_0g.y);
+ p_status->base.accZ |= (s16)((s16)((s16)((s16)data[HID_IDX_BYTE8] >> 1) & (s16)0x0030) |
+ (s16)((s16)(u16)(data[HID_IDX_BYTE7] >> 3) & (s16)0x000C));
+
+ p_status->base.obj[2].x = (s16)((s16)((u16)data[HID_IDX_BYTE10] & 0xFF) |
+ (u16)((u16)(data[HID_IDX_BYTE12] & 0x30) << 4));
+ p_status->base.obj[2].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(data[HID_IDX_BYTE11])) & 0xFF) | (u16)(((u16)(data[HID_IDX_BYTE12] & 0xC0)) << 2)));
+ p_status->exp[2].pixel = (u16)(((s16)((s16)(((u16)(data[HID_IDX_BYTE17]) << 8) & 0xFF00) | (u16)(data[HID_IDX_BYTE18] & 0xFF))) * 64);
+ p_status->exp[2].radius = (s8)((data[HID_IDX_BYTE12] & 0x0f));
+ p_status->exp[2].range_x1 = (s16)(((s8)(data[HID_IDX_BYTE13]) == -1) ? 0 : data[HID_IDX_BYTE13]);
+ p_status->exp[2].range_y1 = (s16)(((s8)(data[HID_IDX_BYTE14]) == -1) ? 0 : data[HID_IDX_BYTE14]);
+ p_status->exp[2].range_x2 = (s16)(((s8)(data[HID_IDX_BYTE15]) == -1) ? 0 : data[HID_IDX_BYTE15]);
+ p_status->exp[2].range_y2 = (s16)(((s8)(data[HID_IDX_BYTE16]) == -1) ? 0 : data[HID_IDX_BYTE16]);
+ p_status->exp[2].range_x1 = (s16)(p_status->exp[2].range_x1 * 8);
+ p_status->exp[2].range_y1 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[2].range_y1 * 8));
+ p_status->exp[2].range_x2 = (s16)(p_status->exp[2].range_x2 * 8);
+ p_status->exp[2].range_y2 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[2].range_y2 * 8));
+ p_status->base.obj[2].size = (u16)((f32)p_status->exp[2].radius * (f32)p_status->exp[2].radius * PI);
+ if (p_status->base.obj[2].size == 0 || p_status->base.obj[2].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) ||
+ p_status->base.obj[2].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1) || p_status->exp[2].radius == 0xf) {
+ p_status->base.obj[2].x = (s16)0;
+ p_status->base.obj[2].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ p_status->base.obj[2].size = 0;
+ p_status->exp[2].pixel = 0;
+ p_status->exp[2].radius = 0;
+ }
+ p_status->base.obj[2].traceId = 2;
+
+ p_status->base.obj[3].x = (s16)((s16)((u16)data[HID_IDX_BYTE19] & 0xFF) |
+ (u16)((u16)(data[HID_IDX_BYTE21] & 0x30) << 4));
+ p_status->base.obj[3].y =
+ (s16)(WPAD_DPD_IMG_RESO_WY - 1 - (s16)((s16)(((u16)(data[HID_IDX_BYTE20])) & 0xFF) | (u16)(((u16)(data[HID_IDX_BYTE21] & 0xC0)) << 2)));
+ p_status->exp[3].pixel = (u16)(((s16)((s16)(((u16)(data[HID_IDX_BYTE26]) << 8) & 0xFF00) | (u16)(data[HID_IDX_BYTE27] & 0xFF))) * 64);
+ p_status->exp[3].radius = (s8)((data[HID_IDX_BYTE21] & 0x0f));
+ p_status->exp[3].range_x1 = (s16)(((s8)(data[HID_IDX_BYTE22]) == -1) ? 0 : data[HID_IDX_BYTE22]);
+ p_status->exp[3].range_y1 = (s16)(((s8)(data[HID_IDX_BYTE23]) == -1) ? 0 : data[HID_IDX_BYTE23]);
+ p_status->exp[3].range_x2 = (s16)(((s8)(data[HID_IDX_BYTE24]) == -1) ? 0 : data[HID_IDX_BYTE24]);
+ p_status->exp[3].range_y2 = (s16)(((s8)(data[HID_IDX_BYTE25]) == -1) ? 0 : data[HID_IDX_BYTE25]);
+ p_status->exp[3].range_x1 = (s16)(p_status->exp[3].range_x1 * 8);
+ p_status->exp[3].range_y1 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[3].range_y1 * 8));
+ p_status->exp[3].range_x2 = (s16)(p_status->exp[3].range_x2 * 8);
+ p_status->exp[3].range_y2 = (s16)((s16)(WPAD_DPD_IMG_RESO_WY - 1) - (s16)(p_status->exp[3].range_y2 * 8));
+ p_status->base.obj[3].size = (u16)((f32)p_status->exp[3].radius * (f32)p_status->exp[3].radius * PI);
+ if (p_status->base.obj[3].size == 0 || p_status->base.obj[3].x == (s16)(WPAD_DPD_IMG_RESO_WX - 1) ||
+ p_status->base.obj[3].y == (s16)(WPAD_DPD_IMG_RESO_WY - 1) || p_status->exp[3].radius == 0xf) {
+ p_status->base.obj[3].x = (s16)0;
+ p_status->base.obj[3].y = (s16)(WPAD_DPD_IMG_RESO_WY - 1);
+ p_status->base.obj[3].size = 0;
+ p_status->exp[3].pixel = 0;
+ p_status->exp[3].radius = 0;
+ }
+
+ p_status->base.obj[3].traceId = 3;
+ old = OSDisableInterrupts();
+ _recv_3f[chan] = 1;
+ if (_recv_3e[chan] && _recv_3f[chan]) {
+ p_status->base.accZ -= p_cb->devConf.acc_0g.z;
+ p_cb->rxBufIndex = (u8)((p_cb->rxBufIndex) ? 0 : 1);
+ _recv_3e[chan] = _recv_3f[chan] = 0;
+ }
+ OSRestoreInterrupts(old);
+}
+
+void __a1_unused_report(u8 chan, u8* data) {}
diff --git a/src/revolution/wpad/WPADMem.c b/src/revolution/wpad/WPADMem.c
new file mode 100644
index 0000000000..efbcc8b9e5
--- /dev/null
+++ b/src/revolution/wpad/WPADMem.c
@@ -0,0 +1,3 @@
+#include <revolution/wpad/__wpad.h>
+
+WPADMEMControlBlock _wmb[WPAD_MAX_CONTROLLERS];
diff --git a/src/revolution/wpad/__wpad.h b/src/revolution/wpad/__wpad.h
index 1bfb13099c..2c5329a221 100644
--- a/src/revolution/wpad/__wpad.h
+++ b/src/revolution/wpad/__wpad.h
@@ -190,7 +190,7 @@ extern "C" {
#define RPT3E_DPD1 1
#define RPT3E_DPD1_OFFSET 13
-/* Report 0x3e: Buttons, Accelerometer (Interleaved 2), IR Camera (Full 2,
+/* Report 0x3f: Buttons, Accelerometer (Interleaved 2), IR Camera (Full 2,
* 18 bytes)
*/
#define RPTID_DATA_BTN_ACC_DPD18_2 0x3f
@@ -226,13 +226,15 @@ extern "C" {
*/
// Speaker register addresses
-#define WM_REG_SPEAKER_01 WM_EXT_REG_ADDR(SPEAKER, 0x01)
-#define WM_REG_SPEAKER_08 WM_EXT_REG_ADDR(SPEAKER, 0x08)
-#define WM_REG_SPEAKER_09 WM_EXT_REG_ADDR(SPEAKER, 0x09)
+#define SPK_RST_REG WM_EXT_REG_ADDR(SPEAKER, 0x01)
+#define SPK_CTRL_REG WM_EXT_REG_ADDR(SPEAKER, 0x08)
+#define SPK_CLK_REG WM_EXT_REG_ADDR(SPEAKER, 0x09)
// Extension register addresses
#define WM_REG_EXTENSION_CONFIG WM_EXT_REG_ADDR(EXTENSION, 0x20)
#define WM_REG_EXTENSION_40 WM_EXT_REG_ADDR(EXTENSION, 0x40)
+#define WM_REG_EXTENSION_46 WM_EXT_REG_ADDR(EXTENSION, 0x46)
+#define WM_REG_EXTENSION_4C WM_EXT_REG_ADDR(EXTENSION, 0x4c)
#define WM_REG_EXTENSION_CERT_PARAM WM_EXT_REG_ADDR(EXTENSION, 0x50)
#define WM_REG_EXTENSION_F0 WM_EXT_REG_ADDR(EXTENSION, 0xf0)
#define WM_REG_EXTENSION_CERT_CHALLENGE WM_EXT_REG_ADDR(EXTENSION, 0xf1)
@@ -266,39 +268,129 @@ extern "C" {
#define WPAD_NZFILTER_MPLS 3
#define WPAD_MAX_NZFILTERS 4
+#define WPAD_DPD_IMG_RESO_WX 1024
+#define WPAD_DPD_IMG_RESO_WY 768
+
+#define WPAD_STATE_DISABLED 0
+#define WPAD_STATE_ENABLING 1
+#define WPAD_STATE_ENABLED 2
+#define WPAD_STATE_SETUP 3
+#define WPAD_STATE_DISABLING 4
+
+#define WPAD_BATTERY_LEVEL_CRITICAL 0
+#define WPAD_BATTERY_LEVEL_LOW 1
+#define WPAD_BATTERY_LEVEL_MEDIUM 2
+#define WPAD_BATTERY_LEVEL_HIGH 3
+#define WPAD_BATTERY_LEVEL_MAX 4
#define WPAD_RADIO_QUALITY_GOOD 0 // 80+
#define WPAD_RADIO_QUALITY_BAD 1 // 80-
-struct WPADCmd {
- /* 0x00 */ u32 reportID;
- /* 0x04 */ u8 dataBuf[RPT_MAX_SIZE];
- /* 0x1a */ u16 dataLength;
- /* 0x1c */ void* dstBuf;
- /* 0x20 */ u16 readLength;
- /* 0x24 */ u32 readAddress;
- /* 0x28 */ WPADInfo* statusReportOut;
- /* 0x2c */ WPADCallback cmdCB;
-}; // size 0x30
-struct WPADCmdQueue {
- /* 0x00 */ s8 indexOut;
- /* 0x01 */ s8 indexIn;
- /* 0x04 */ struct WPADCmd* queue;
- /* 0x08 */ u32 length;
-}; // size 0x0c
-
-struct WPADDevConfig {
- /* 0x00 */ DPDObject dpd[WPAD_MAX_DPD_OBJECTS];
- /* 0x20 */ s16 accX0g;
- /* 0x22 */ s16 accY0g;
- /* 0x24 */ s16 accZ0g;
- /* 0x26 */ s16 accX1g;
- /* 0x28 */ s16 accY1g;
- /* 0x2a */ s16 accZ1g;
- /* 0x2c */ u8 motor;
- /* 0x2d */ u8 volume;
- /* 0x30 */ u8 pad0_[2];
-};
+#define WPAD_SENSOR_BAR_POS_BOTTOM 0
+#define WPAD_SENSOR_BAR_POS_TOP 1
+
+#define WPAD_RX_DATASIZE 96
+#define WPAD_COMMAND_CMD_MAX_LEN 24
+#if PLATFORM_SHIELD
+#define WPAD_COMMAND_EXT_MAX_LEN 12
+#else
+#define WPAD_COMMAND_EXT_MAX_LEN 8
+#endif
+#define WPAD_COMMAND_BUF_LEN 22
+
+#define WPAD_I2CDEV_SEL_MASK (u32)(0xFF000000)
+#define WPAD_I2CDEV_DADR_MASK (u32)(0x00FF0000)
+#define WPAD_I2CDEV_UADR_MASK (u32)(0x0000FF00)
+#define WPAD_I2CDEV_LADR_MASK (u32)(0x000000FF)
+#define WPAD_WRITE_LEN_MASK (u16)(0x001F)
+#define WPAD_READ_ULEN_MASK (u16)(0xFF00)
+#define WPAD_READ_LLEN_MASK (u16)(0x00FF)
+
+#define SPK_CLK_OFF 0x00
+#define SPK_CLK_ON 0x01
+#define SPK_DERESET 0x01
+#if SDK_AUG2010
+#define SPK_RESET 0x80
+#else
+#define SPK_RESET 0x08
+#endif
+#define SPK_CTRL_PLAY 0x01
+
+// Utility macros to help with SDK version differences
+
+#if SDK_AUG2010
+#define DIFF_COUNT_DPD(p_wpd) (p_wpd->filterDiff[WPAD_NZFILTER_DPD])
+#define HYST_COUNT_DPD(p_wpd) (p_wpd->filterSame[WPAD_NZFILTER_DPD])
+#define DIFF_COUNT_ACC(p_wpd) (p_wpd->filterDiff[WPAD_NZFILTER_ACC])
+#define HYST_COUNT_ACC(p_wpd) (p_wpd->filterSame[WPAD_NZFILTER_ACC])
+#define DIFF_COUNT_FS_ACC(p_wpd) (p_wpd->filterDiff[WPAD_NZFILTER_EXT])
+#define HYST_COUNT_FS_ACC(p_wpd) (p_wpd->filterSame[WPAD_NZFILTER_EXT])
+#else
+#define DIFF_COUNT_DPD(p_wpd) (p_wpd->diffCountDpd)
+#define HYST_COUNT_DPD(p_wpd) (p_wpd->hystCountDpd)
+#define DIFF_COUNT_ACC(p_wpd) (p_wpd->diffCountAcc)
+#define HYST_COUNT_ACC(p_wpd) (p_wpd->hystCountAcc)
+#define DIFF_COUNT_FS_ACC(p_wpd) (p_wpd->diffCountfsAcc)
+#define HYST_COUNT_FS_ACC(p_wpd) (p_wpd->hystCountfsAcc)
+#endif
+
+typedef struct WPADUnkStatus {
+ /* 0x00 */ WPADStatus base;
+ /* 0x2A */ u8 field_0x2a[0x60 - 0x2a];
+} WPADUnkStatus;
+
+typedef struct WPADMEMGameInfo {
+ /* 0x00 */ OSTime calendarTimeTick;
+ /* 0x08 */ u16 gameTitle[17];
+ /* 0x2A */ char gameId[4];
+ /* 0x2E */ u8 gameType;
+ /* 0x2F */ u8 checkSum;
+ /* 0x30 */ u8 reserved[8];
+} WPADMEMGameInfo;
+
+typedef struct WPADMemBlock {
+ /* 0x00 */ BOOL busy;
+ /* 0x04 */ const u8* data;
+ /* 0x08 */ BOOL len;
+ /* 0x0C */ BOOL addr;
+ /* 0x10 */ WPADCallback* cb;
+} WPADMemBlock;
+
+typedef struct WPADCommand {
+ /* 0x00 */ u32 command;
+ /* 0x04 */ u8 data[22];
+ /* 0x1A */ u16 len;
+ /* 0x1C */ void* readBuf;
+ /* 0x20 */ u16 readLen;
+ /* 0x24 */ u32 readAddr;
+ /* 0x28 */ WPADInfo* info;
+ /* 0x2C */ WPADCallback callback;
+} WPADCommand;
+
+typedef struct WPADCmdQueue {
+ /* 0x00 */ s8 head;
+ /* 0x01 */ s8 tail;
+ /* 0x04 */ WPADCommand* cmd;
+ /* 0x08 */ u32 cmdlen;
+} WPADCmdQueue;
+
+typedef struct WPADDevConfig {
+ /* 0x00 */ DPDObject obj[WPAD_DPD_MAX_OBJECTS];
+ /* 0x20 */ WPADAcc acc_0g;
+ /* 0x26 */ WPADAcc acc_1g;
+ /* 0x2C */ u8 motor;
+ /* 0x2D */ u8 volume;
+ /* 0x2E */ u8 unk_0x2e[0x30 - 0x2e];
+} WPADDevConfig;
+
+typedef struct WPADStick {
+ /* 0x00 */ s16 x;
+ /* 0x02 */ s16 x_min;
+ /* 0x04 */ s16 x_max;
+ /* 0x06 */ s16 y;
+ /* 0x08 */ s16 y_min;
+ /* 0x0A */ s16 y_max;
+} WPADStick;
typedef struct WPADMplsCalibration {
/* 0x00 */ f32 pitchZero;
@@ -310,109 +402,84 @@ typedef struct WPADMplsCalibration {
/* 0x18 */ s32 degrees;
} WPADMplsCalibration;
-struct WPADExtConfig {
- union {
- struct WPADFSConfig {
- /* 0x00 */ s16 stickXCenter;
- /* 0x02 */ s16 at_0x02;
- /* 0x04 */ s16 at_0x04;
- /* 0x06 */ s16 stickYCenter;
- /* 0x08 */ s16 at_0x08;
- /* 0x0a */ s16 at_0x0a;
- /* 0x0c */ s16 accX0g;
- /* 0x0e */ s16 accY0g;
- /* 0x10 */ s16 accZ0g;
- /* 0x12 */ s16 accX1g;
- /* 0x14 */ s16 accY1g;
- /* 0x16 */ s16 accZ1g;
- } fs; // size 0x1a
-
- struct WPADCLConfig {
- /* 0x00 */ s16 lStickXCenter;
- /* 0x02 */ s16 at_0x02;
- /* 0x04 */ s16 at_0x04;
- /* 0x06 */ s16 lStickYCenter;
- /* 0x08 */ s16 at_0x08;
- /* 0x0a */ s16 at_0x0a;
- /* 0x0c */ s16 rStickXCenter;
- /* 0x0e */ s16 at_0x0e;
- /* 0x10 */ s16 at_0x10;
- /* 0x12 */ s16 rStickYCenter;
- /* 0x14 */ s16 at_0x14;
- /* 0x16 */ s16 at_0x16;
- /* 0x18 */ u8 triggerLZero;
- /* 0x19 */ u8 triggerRZero;
- } cl; // size 0x1a
-
- u8 forceUnionSize_[0x1c]; // alignment?
- }; // size 0x1c
-
+typedef struct WPADFsConfig {
+ /* 0x00 */ WPADStick stick;
+ /* 0x0C */ WPADAcc acc_0g;
+ /* 0x12 */ WPADAcc acc_1g;
+} WPADFsConfig;
+
+typedef struct WPADClConfig {
+ /* 0x00 */ WPADStick lstk;
+ /* 0x0C */ WPADStick rstk;
+ /* 0x18 */ u8 triggerL;
+ /* 0x19 */ u8 triggerR;
+} WPADClConfig;
+
+typedef struct WPADExtConfig {
+ /* 0x00 */ union {
+ WPADFsConfig fs;
+ WPADClConfig cl;
+ u8 bytes[0x1c];
+ };
+#if SDK_AUG2010
struct WPADMplsConfig {
/* 0x00 */ WPADMplsCalibration high;
/* 0x1c */ WPADMplsCalibration low;
/* 0x38 */ u32 calibCRC;
/* 0x3c */ u16 calibID;
} /* 0x1a */ mpls;
-}; // size 0x5c
-
-typedef struct WPADGameInfo {
- /* 0x00 */ OSTime timestamp;
- /* 0x08 */ u16 gameTitle[16 + 1];
- /* 0x2a */ char gameCode[4];
- /* 0x2e */ u8 gameType;
- /* 0x2f */ u8 checksum;
- u8 _pad0[8];
-} WPADGameInfo; // size 0x38
-
-struct WPADMemBlock {
- /* 0x00 */ BOOL busy;
- /* 0x04 */ u8 const* data;
- /* 0x08 */ u16 len;
- /* 0x0c */ u32 addr;
- /* 0x10 */ WPADCallback* cb;
-}; // size 0x14
-
-typedef struct /* possibly untagged, like kpad */ {
- /* 0x000 */ WPADGameInfo gameInfo;
- /* 0x038 */ s32 at_0x038[2]; /* unknown */ // WPADResult[2]? see __wpadGetGameInfo
- /* 0x040 */ u8 rxBufMain[RX_BUFFER_SIZE];
- /* 0x0a0 */ u8 rxBufs[2][RX_BUFFER_SIZE];
- /* 0x160 */ struct WPADCmdQueue stdCmdQueue;
- /* 0x16c */ struct WPADCmd stdCmdQueueList[24];
- /* 0x5ec */ struct WPADCmdQueue extCmdQueue;
- /* 0x16c */ struct WPADCmd extCmdQueueList[12];
- /* 0x838 */ WPADInfo info;
- /* 0x850 */ WPADInfo* infoOut;
- /* 0x854 */ struct WPADDevConfig devConfig;
- /* 0x884 */ struct WPADExtConfig extConfig;
- /* 0x8e0 */ WPADCallback cmdBlkCB;
- /* 0x8e4 */ WPADExtensionCallback extensionCB;
- /* 0x8e8 */ WPADConnectCallback connectCB;
- /* 0x8ec */ WPADSamplingCallback samplingCB;
- /* 0x8f0 */ void* samplingBuf;
- /* 0x8f4 */ u32 samplingBufIndex;
- /* 0x8f8 */ u32 samplingBufSize;
- /* 0x8fc */ u32 dataFormat;
- /* 0x900 */ s32 status;
- /* 0x904 */ u8 statusReqBusy;
- /* 0x905 */ u8 devType;
- /* 0x906 */ u8 devMode;
- /* 0x907 */ s8 devHandle;
+#endif
+} WPADExtConfig;
+
+typedef struct WPADControlBlock {
+ /* 0x000 */ WPADMEMGameInfo gameInfo;
+ /* 0x038 */ s32 gameInfoErr[2];
+ /* 0x040 */ WPADUnkStatus prBuf[1];
+ /* 0x0A0 */ WPADUnkStatus rxBufs[2];
+ /* 0x160 */ WPADCmdQueue stdCmdQueue;
+ /* 0x16C */ WPADCommand stdCmdQueueList[WPAD_COMMAND_CMD_MAX_LEN];
+ /* 0x5EC */ WPADCmdQueue extCmdQueue;
+ /* 0x5F8 */ WPADCommand extCmdQueueList[WPAD_COMMAND_EXT_MAX_LEN];
+ /* 0x778 */ WPADInfo info;
+ /* 0x790 */ WPADInfo* infoOut;
+ /* 0x794 */ WPADDevConfig devConf;
+ /* 0x7C4 */ WPADExtConfig extConf;
+ /* 0x7DC */ WPADCallback cmdBlkCallback;
+ /* 0x7E0 */ WPADExtensionCallback extensionCallback;
+ /* 0x7E4 */ WPADConnectCallback connectCallback;
+ /* 0x7E8 */ WPADSamplingCallback samplingCallback;
+ /* 0x7EC */ void* samplingBufs_ptr;
+ /* 0x7F0 */ u32 samplingBufIndex;
+ /* 0x7F4 */ u32 samplingBufLength;
+ /* 0x7F8 */ u32 dataFormat;
+ /* 0x7FC */ s32 status;
+ /* 0x800 */ u8 statusReqBusy;
+ /* 0x801 */ u8 devType;
+ /* 0x802 */ u8 devMode;
+ /* 0x803 */ s8 devHandle;
+#if SDK_AUG2010
/* 0x908 */ int at_0x908; /* unknown */
/* 0x90c */ u8 rxBufIndex;
/* 0x90d */ s8 at_0x90d; /* unknown */
- /* 0x90e */ u8 defaultDpdSize; // maybe?
+ /* 0x90e */ u8 dpdDummyObjSize; // maybe?
/* 0x90f */ u8 currentDpdCommand;
/* 0x910 */ u8 pendingDpdCommand;
- /* 0x911 */ u8 radioQuality;
- /* 0x912 */ u8 radioQualityOkMs; // see __wpadCalcRadioQuality
- /* 0x913 */ u8 audioFrames;
- /* 0x914 */ u32 motorBusy;
- /* 0x918 */ BOOL motorRunning;
- /* 0x91c */ BOOL used;
- /* 0x920 */ BOOL handshakeFinished;
- /* 0x924 */ int configIndex;
- /* 0x928 */ OSThreadQueue threadQueue; /* purpose unknown */
+#else
+ /* 0x804 */ u16 dpdDummyObjSize;
+ /* 0x806 */ u8 rxBufIndex;
+ /* 0x807 */ u8 reqVolume;
+ /* 0x808 */ WPADCallback reqVolCb;
+#endif
+ /* 0x80C */ u8 radioQuality;
+ /* 0x80D */ u8 radioQualityOkMs; // see __wpadCalcRadioQuality
+ /* 0x80E */ u8 audioFrames;
+ /* 0x810 */ BOOL motorBusy;
+ /* 0x814 */ BOOL motorRunning;
+ /* 0x818 */ BOOL used;
+ /* 0x81C */ BOOL handshakeFinished;
+ /* 0x820 */ BOOL oldFw;
+ /* 0x824 */ OSThreadQueue threadQueue;
+#if SDK_AUG2010
/* 0x930 */ WPADCallback vsmCallback;
/* 0x934 */ u8 controlMplsBusy;
/* 0x935 */ u8 mplsCBReadBuf[2];
@@ -436,26 +503,36 @@ typedef struct /* possibly untagged, like kpad */ {
/* 0x994 */ u32 certLintY[1 + 16 + 1];
/* 0x994 */ u32 certLintBig[LINT_NUM_MAX_BUFSIZ];
/* 0xae4 */ int at_0xae4; /* unknown */
- /* 0xae8 */ OSTime lastControllerDataUpdate;
+#endif
+ /* 0x830 */ OSTime lastUpdateTime;
+#if SDK_AUG2010
/* 0xaf0 */ u16 filterDiff[WPAD_MAX_NZFILTERS];
/* 0xaf8 */ u16 filterSame[WPAD_MAX_NZFILTERS];
- /* 0xb00 */ OSTime lastReportSendTime;
- /* 0xb08 */ u8 at_0xb08; /* unknown */
- /* 0xb09 */ u8 calibrated;
- /* 0xb0a */ u16 recalibHoldMs;
- /* 0xb0c */ u8 encryptionKey[16];
- /* 0xb1c */ u8 decryptAddTable[8];
- /* 0xb24 */ u8 decryptXorTable[8];
- /* 0xb2c */ u8 wmReadDataBuf[64];
- /* 0xb6c */ u8* wmReadDataPtr;
- /* 0xb70 */ u32 wmReadAddress;
- /* 0xb74 */ int wmReadHadError;
- /* 0xb78 */ u16 wmReadLength;
- /* 0xb7a */ s8 at_0xb7a; /* unknown */
- /* 0xb7b */ u8 radioSensitivity;
- /* 0xb7c */ u16 copyOutCount;
- /* 0xb7e */ u8 sleeping;
- /* 0xb7f */ u8 lastReportID;
+#else
+ /* 0x838 */ u16 diffCountDpd;
+ /* 0x83A */ u16 hystCountDpd;
+ /* 0x83C */ u16 diffCountAcc;
+ /* 0x83E */ u16 hystCountAcc;
+ /* 0x840 */ u16 diffCountfsAcc;
+ /* 0x842 */ u16 hystCountfsAcc;
+#endif
+ /* 0x844 */ OSTime lastReportSendTime;
+ /* 0x850 */ u8 cmdTimeoutAction;
+ /* 0x851 */ u8 calibrated;
+ /* 0x852 */ u16 recalibrateCount;
+ /* 0x854 */ u8 key[16];
+ /* 0x864 */ u8 ft[8];
+ /* 0x86C */ u8 sb[8];
+ /* 0x874 */ u8 wmReadDataBuf[64];
+ /* 0x8B4 */ void* wmReadDataPtr;
+ /* 0x8B8 */ u32 wmReadAddr;
+ /* 0x8BC */ s32 wmReadErr;
+ /* 0x8C0 */ u16 wmReadLength;
+ /* 0x8C2 */ u8 keyIdx;
+ /* 0x8C3 */ u8 radioSensitivity;
+ /* 0x8C4 */ u16 packetCnt;
+ /* 0x8C6 */ u8 disconnect;
+ /* 0x8C7 */ u8 lastReportId;
/* 0xb80 */ WPADCallback getInfoCB;
/* 0xb84 */ u8 getInfoBusy;
/* 0xb85 */ u8 extState;
@@ -464,7 +541,7 @@ typedef struct /* possibly untagged, like kpad */ {
/* 0xb88 */ u8 savedDevType; // maybe?
/* 0xb89 */ u8 extWasDisconnected;
/* 0xb8a */ s16 reconnectExtMs;
- /* 0xb8c */ struct WPADMemBlock memBlock;
+ /* 0xb8c */ WPADMemBlock memBlock;
/* 0xba0 */ WPADCallback controlMplsCB;
/* 0xba4 */ u8 parseMPBuf;
/* 0xba5 */ u8 certProbeByte;
@@ -474,7 +551,7 @@ typedef struct /* possibly untagged, like kpad */ {
/* 0xbac */ u8 mplsCBState;
/* 0xbad */ u8 mplsUptimeMs;
/* 0xbae */ s8 certMayVerifyByCalibBlock;
- u8 pad0_[2]; /* unknown (can't be alignment) */
+ /* 0xbaf */ u8 unk_0xbaf[0xbb1 - 0xbaf]; /* unknown (can't be alignment) */
/* 0xbb1 */ u8 certProbeStartingValue;
/* 0xbb2 */ u16 lastMplsCalibID;
/* 0xbb4 */ u32 lastMplsCalibCRC;
@@ -484,17 +561,90 @@ typedef struct /* possibly untagged, like kpad */ {
/* 0xbbb */ u8 extDevType;
/* 0xbbc */ u8 currPwmDuty;
/* 0xbbd */ u8 pendingPwmDuty;
- u8 pad1_[2]; /* unknown (can't be alignment) */
+ /* 0xbbe */ u8 unk_0xbbe[0xbc0 - 0xbbe]; /* unknown (can't be alignment) */
/* 0xbc0 */ u8 extDataBuf[32];
-} ATTRIBUTE_ALIGN(32) wpad_cb_st; // size 0xbe0
-
-BOOL WPADiIsAvailableCmdQueue(struct WPADCmdQueue* cmdQueue, s8 num);
-BOOL WPADiSendWriteDataCmd(struct WPADCmdQueue* cmdQueue, u8 cmd, u32 address, WPADCallback cb);
-BOOL WPADiSendWriteData(struct WPADCmdQueue* cmdQueue, void const* p_buf, u16 len, u32 address, WPADCallback cb);
-BOOL WPADiSendStreamData(struct WPADCmdQueue* cmdQueue, void const* p_buf, u16 len);
-BOOL WPADiSendMuteSpeaker(struct WPADCmdQueue* cmdQueue, BOOL muted, WPADCallback cb);
-BOOL WPADiSendEnableSpeaker(struct WPADCmdQueue* cmdQueue, BOOL enabled, WPADCallback cb);
-BOOL WPADiSendGetContStat(struct WPADCmdQueue* cmdQueue, WPADInfo* infoOut, WPADCallback cb);
+} WPADControlBlock;
+
+typedef struct WPADMEMControlBlock {
+ /* 0x00 */ BOOL used;
+ /* 0x04 */ u8* p_buf;
+ /* 0x08 */ u16 len;
+ /* 0x0C */ u32 addr;
+ /* 0x10 */ WPADCallback callback;
+} WPADMEMControlBlock;
+
+struct WPADCmd {
+ /* 0x00 */ u32 reportID;
+ /* 0x04 */ u8 dataBuf[RPT_MAX_SIZE];
+ /* 0x1a */ u16 dataLength;
+ /* 0x1c */ void* dstBuf;
+ /* 0x20 */ u16 readLength;
+ /* 0x24 */ u32 readAddress;
+ /* 0x28 */ WPADInfo* statusReportOut;
+ /* 0x2c */ WPADCallback cmdCB;
+}; // size 0x30
+
+extern WPADMEMControlBlock _wmb[WPAD_MAX_CONTROLLERS];
+#if SDK_AUG2010
+extern WPADControlBlock* __rvl_p_wpadcb[WPAD_MAX_CONTROLLERS];
+#define _wpdcb __rvl_p_wpadcb
+#else
+extern WPADControlBlock* _wpdcb[WPAD_MAX_CONTROLLERS];
+#endif
+
+/* WPAD.c */
+
+void WPADiCreateKey(s32);
+void WPADiCreateKeyFor3rd(s32);
+s32 WPADiHIDParser(u8 chan, u8* p_rpt);
+
+void WPADiClearQueue(WPADCmdQueue* queue);
+BOOL WPADiSendSetReportType(WPADCmdQueue* queue, u32 fmt, WPADCallback callback);
+BOOL WPADiSendWriteDataCmd(WPADCmdQueue* queue, u8 cmd, u32 addr, WPADCallback callback);
+BOOL WPADiSendReadData(WPADCmdQueue* queue, void* p_buf, u16 len, u32 addr, WPADCallback callback);
+BOOL WPADiSendWriteData(WPADCmdQueue* queue, void* p_buf, u16 len, u32 addr, WPADCallback callback);
+
+void WPADiCopyOut(s32 chan);
+u32 WPADGetLatestIndexInBuf(s32 chan, void* buf);
+void WPADiExcludeButton(s32 chan);
+s32 WPADiGetStatus(s32 chan);
+
+void WPADiShutdown(BOOL exec);
+void WPADiDisconnect(s32 chan, BOOL polite);
+
+BOOL WPADiSendSetPort(WPADCmdQueue* queue, u8 pattern, WPADCallback callback);
+BOOL WPADiSendDPDCSB(WPADCmdQueue* queue, BOOL enable, WPADCallback callback);
+#if SDK_AUG2010
+BOOL WPADiSendGetContStat(WPADCmdQueue* queue, WPADInfo* info, WPADCallback callback);
+#else
+BOOL WPADiSendGetContStat(WPADCmdQueue* queue, WPADInfo* info, u32 addr, WPADCallback callback);
+#endif
+void WPADiCheckContInputs(s32 chan);
+
+s32 WPADiRetrieveChannel(u8 dev_handle);
+s32 WPADiSendData(s32 chan, WPADCommand cmd);
+
+BOOL WPADiGetCommand(WPADCmdQueue* queue, WPADCommand* cmd);
+BOOL WPADiPopCommand(WPADCmdQueue* queue);
+BOOL __wpadPushCommand(WPADCmdQueue* queue, WPADCommand cmd);
+BOOL WPADiProcessCommand(s32 chan);
+BOOL WPADiProcessExtCommand(s32 chan);
+void WPADiRumbleMotor(s32 chan, BOOL sendCmd);
+void WPADiRadioSensitivity(s32 chan);
+
+void WPADiContMapTableUpdate(void);
+void WPADiAfh(void);
+void WPADiGetScSettings(void);
+
+void WPADiConnCallback(u8 dev_handle, u8 open);
+void WPADiRecvCallback(u8 dev_handle, u8* p_rpt, u16);
+
+/* WPADEncrypt.c */
+void WPADiCreateKey(s32 chan);
+void WPADiDecode(s32 chan, void* p_buf, u16 len, u16 offset);
+
+/* wpad_debug_msg.c */
+void DEBUGPrint(const char* fmt, ...);
#ifdef __cplusplus
}
diff --git a/src/revolution/wpad/wpad_debug_msg.c b/src/revolution/wpad/wpad_debug_msg.c
new file mode 100644
index 0000000000..2713ba81c9
--- /dev/null
+++ b/src/revolution/wpad/wpad_debug_msg.c
@@ -0,0 +1,5 @@
+#include <revolution/wpad/__wpad.h>
+
+void DEBUGPrint(const char* fmt, ...) {
+ // NONMATCHING
+}
diff --git a/src/revolution/wpad/WUD.c b/src/revolution/wud/WUD.c
index 54685342a8..9c38c36731 100644
--- a/src/revolution/wpad/WUD.c
+++ b/src/revolution/wud/WUD.c
@@ -1,7 +1,9 @@
-#include <revolution/os.h>
-#include <revolution/wpad/wud.h>
+#include <revolution/wud/WUD.h>
+#include <revolution/os.h>
+#include <revolution/wud/debug_msg.h>
#include "__wud.h"
+#include "types.h"
wud_cb_st __rvl_wudcb;
@@ -61,3 +63,11 @@ u16 WUDiGetQueueSizeForHandle(u8 dev_handle) {
u16 WUDiGetNotAckNumForHandle(u8 dev_handle) {
return _dev_handle_notack_num[dev_handle];
}
+
+BOOL WUDStartSyncSimple(void) {
+ // NONMATCHING
+}
+
+BOOL WUDStartFastSyncSimple(void) {
+ // NONMATCHING
+}
diff --git a/src/revolution/wpad/__wud.h b/src/revolution/wud/__wud.h
index 0f3c2499b0..dace1a2f71 100644
--- a/src/revolution/wpad/__wud.h
+++ b/src/revolution/wud/__wud.h
@@ -3,7 +3,6 @@
#include <revolution/os.h>
#include <revolution/wpad/bte.h>
-#include <revolution/wpad/wud.h>
#ifdef __cplusplus
extern "C" {
diff --git a/src/revolution/wud/debug_msg.c b/src/revolution/wud/debug_msg.c
new file mode 100644
index 0000000000..43ab011cb5
--- /dev/null
+++ b/src/revolution/wud/debug_msg.c
@@ -0,0 +1,6 @@
+#include <revolution/wud/debug_msg.h>
+
+void WUD_DEBUGPrint(const char* msg, ...) {
+ // NONMATCHING
+}
+