diff options
| author | Max Roncace <me@caseif.net> | 2026-02-03 02:17:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-02 23:17:29 -0800 |
| commit | 3bc0670b910c4d638dfff81da67e5a95009183cb (patch) | |
| tree | 22a501d99df41bee95a730acefd6cfd2d8b2c954 /src | |
| parent | 67f179161f04805654fbb078ad2996837f8acb27 (diff) | |
Revolution WUD work (mostly matching) (#3080)
* WUD mostly matching for Wii
Mostly copied from Petari with small modifications, Shield match is
still pretty bad.
* Implement WUDHidHost
* Fix WUD regressions in Shield/ShieldD
Diffstat (limited to 'src')
| -rw-r--r-- | src/revolution/wpad/WPAD.c | 22 | ||||
| -rw-r--r-- | src/revolution/wpad/__wpad.h | 72 | ||||
| -rw-r--r-- | src/revolution/wud/WUD.c | 2883 | ||||
| -rw-r--r-- | src/revolution/wud/WUDHidHost.c | 261 | ||||
| -rw-r--r-- | src/revolution/wud/__wud.h | 260 | ||||
| -rw-r--r-- | src/revolution/wud/debug_msg.c | 6 |
6 files changed, 3384 insertions, 120 deletions
diff --git a/src/revolution/wpad/WPAD.c b/src/revolution/wpad/WPAD.c index 6f01d6e459..9bdbe70b04 100644 --- a/src/revolution/wpad/WPAD.c +++ b/src/revolution/wpad/WPAD.c @@ -1,11 +1,12 @@ #include <revolution/wpad.h> #include <revolution/wpad/__wpad.h> -#include <revolution/wud/WUD.h> +#include <revolution/wud.h> #include <revolution/dvd.h> #include <revolution/sc.h> #include <revolution/vi.h> #include <revolution/wpad/bte.h> +#include <revolution/wud/__wud.h> #include <cstdio> #include <cstring> @@ -14,7 +15,11 @@ 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]; +#if SDK_AUG2010 +WPADControlBlock* __rvl_p_wpadcb[WPAD_MAX_CONTROLLERS]; +#else WPADControlBlock* _wpdcb[WPAD_MAX_CONTROLLERS]; +#endif u8 _sleepTime; u8 _dpdSensitivity; @@ -89,7 +94,7 @@ BOOL OnShutdown(BOOL final, u32 event) { _shutdown = TRUE; WUDSetVisibility(0, 0); for (i = 10; i < 14; i++) { - memset(&_scArray.info[i], 0, sizeof(_scArray.info[i])); + memset(&_scArray.regist[i], 0, sizeof(_scArray.regist[i])); } OSCancelAlarm(&_managerAlarm); WUDSetHidRecvCallback(NULL); @@ -1030,7 +1035,7 @@ s32 WPADiRetrieveChannel(u8 dev_handle) { devAddr = _WUDGetDevAddr(dev_handle); for (i = 0; i < WPAD_MAX_CONTROLLERS; i++) { - if (!memcmp(_scArray.info[i + 10].bd_addr, devAddr, 6)) { + if (!memcmp(_scArray.regist[i + 10].addr, devAddr, 6)) { if (_chan_active_state[i] == 0) { _chan_active_state[i] = 1; return i; @@ -1040,7 +1045,7 @@ s32 WPADiRetrieveChannel(u8 dev_handle) { 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); + memcpy(_scArray.regist[i + 10].addr, devAddr, 6); _scFlush = 1; return i; } @@ -1319,8 +1324,7 @@ u8 WPADGetSensorBarPosition() { } void WPADDisconnect(s32 chan) { - WPADControlBlock* p_wpd = _wpdcb[chan]; - memset(&_scArray.info[chan + 10], 0, sizeof(SCBtDeviceInfoSingle)); + memset(&_scArray.regist[chan + 10], 0, sizeof(SCBtDeviceInfo)); _scFlush = 1; WPADiDisconnect(chan, TRUE); } @@ -2523,17 +2527,17 @@ void __WPADShutdown() { WUDSetVisibility(0, 0); for (i = 10; i < 14; i++) { - memset(&_scArray.info[i], 0, sizeof(SCBtDeviceInfoSingle)); + memset(&_scArray.regist[i], 0, sizeof(SCBtDeviceInfo)); } WPADiShutdown(FALSE); OSRestoreInterrupts(enable); } -void WPADiShutdown(BOOL exec) { +void WPADiShutdown() { OSCancelAlarm(&_managerAlarm); WUDSetHidRecvCallback(NULL); - WUDShutdown(exec); + WUDShutdown(); } BOOL WPADCancelSyncDevice() { diff --git a/src/revolution/wpad/__wpad.h b/src/revolution/wpad/__wpad.h index 2c5329a221..500183cfae 100644 --- a/src/revolution/wpad/__wpad.h +++ b/src/revolution/wpad/__wpad.h @@ -380,7 +380,9 @@ typedef struct WPADDevConfig { /* 0x26 */ WPADAcc acc_1g; /* 0x2C */ u8 motor; /* 0x2D */ u8 volume; +#if SDK_AUG2010 /* 0x2E */ u8 unk_0x2e[0x30 - 0x2e]; +#endif } WPADDevConfig; typedef struct WPADStick { @@ -419,7 +421,11 @@ typedef struct WPADExtConfig { /* 0x00 */ union { WPADFsConfig fs; WPADClConfig cl; +#if SDK_AUG2010 u8 bytes[0x1c]; +#else + u8 bytes[0x18]; +#endif }; #if SDK_AUG2010 struct WPADMplsConfig { @@ -533,36 +539,40 @@ typedef struct WPADControlBlock { /* 0x8C4 */ u16 packetCnt; /* 0x8C6 */ u8 disconnect; /* 0x8C7 */ u8 lastReportId; - /* 0xb80 */ WPADCallback getInfoCB; - /* 0xb84 */ u8 getInfoBusy; - /* 0xb85 */ u8 extState; - /* 0xb86 */ u8 savePower; - /* 0xb87 */ u8 blcBattery; - /* 0xb88 */ u8 savedDevType; // maybe? - /* 0xb89 */ u8 extWasDisconnected; - /* 0xb8a */ s16 reconnectExtMs; - /* 0xb8c */ WPADMemBlock memBlock; - /* 0xba0 */ WPADCallback controlMplsCB; - /* 0xba4 */ u8 parseMPBuf; - /* 0xba5 */ u8 certProbeByte; - /* 0xba6 */ u8 dpdBusy; - /* 0xba7 */ u8 interleaveFlags; - /* 0xba8 */ u32 mplsCBReadAddress; - /* 0xbac */ u8 mplsCBState; - /* 0xbad */ u8 mplsUptimeMs; - /* 0xbae */ s8 certMayVerifyByCalibBlock; - /* 0xbaf */ u8 unk_0xbaf[0xbb1 - 0xbaf]; /* unknown (can't be alignment) */ - /* 0xbb1 */ u8 certProbeStartingValue; - /* 0xbb2 */ u16 lastMplsCalibID; - /* 0xbb4 */ u32 lastMplsCalibCRC; - /* 0xbb8 */ u8 noParseExtCount; - /* 0xbb9 */ s8 extErr; - /* 0xbba */ u8 extDataLength; - /* 0xbbb */ u8 extDevType; - /* 0xbbc */ u8 currPwmDuty; - /* 0xbbd */ u8 pendingPwmDuty; - /* 0xbbe */ u8 unk_0xbbe[0xbc0 - 0xbbe]; /* unknown (can't be alignment) */ - /* 0xbc0 */ u8 extDataBuf[32]; +#if SDK_AUG2010 + /* 0xB80 */ WPADCallback getInfoCB; + /* 0xB84 */ u8 getInfoBusy; + /* 0xB85 */ u8 extState; + /* 0xB86 */ u8 savePower; + /* 0xB87 */ u8 blcBattery; + /* 0xB88 */ u8 savedDevType; // maybe? + /* 0xB89 */ u8 extWasDisconnected; + /* 0xB8A */ s16 reconnectExtMs; + /* 0xB8C */ WPADMemBlock memBlock; + /* 0xBA0 */ WPADCallback controlMplsCB; + /* 0xBA4 */ u8 parseMPBuf; + /* 0xBA5 */ u8 certProbeByte; + /* 0xBA6 */ u8 dpdBusy; + /* 0xBA7 */ u8 interleaveFlags; + /* 0xBA8 */ u32 mplsCBReadAddress; + /* 0xBAC */ u8 mplsCBState; + /* 0xBAD */ u8 mplsUptimeMs; + /* 0xBAE */ s8 certMayVerifyByCalibBlock; + /* 0xBAF */ u8 unk_0xbaf[0xbb1 - 0xbaf]; /* unknown (can't be alignment) */ + /* 0xBB1 */ u8 certProbeStartingValue; + /* 0xBB2 */ u16 lastMplsCalibID; + /* 0xBB4 */ u32 lastMplsCalibCRC; + /* 0xBB8 */ u8 noParseExtCount; + /* 0xBB9 */ s8 extErr; + /* 0xBBA */ u8 extDataLength; + /* 0xBBB */ u8 extDevType; + /* 0xBBC */ u8 currPwmDuty; + /* 0xBBD */ u8 pendingPwmDuty; + /* 0xBBE */ u8 unk_0xbbe[0xbc0 - 0xbbe]; /* unknown (can't be alignment) */ + /* 0xBC0 */ u8 extDataBuf[32]; +#else + /* 0x8C8 */ u8 extDataBuf[0x8e0 - 0x8c8]; +#endif } WPADControlBlock; typedef struct WPADMEMControlBlock { @@ -609,7 +619,7 @@ u32 WPADGetLatestIndexInBuf(s32 chan, void* buf); void WPADiExcludeButton(s32 chan); s32 WPADiGetStatus(s32 chan); -void WPADiShutdown(BOOL exec); +void WPADiShutdown(); void WPADiDisconnect(s32 chan, BOOL polite); BOOL WPADiSendSetPort(WPADCmdQueue* queue, u8 pattern, WPADCallback callback); diff --git a/src/revolution/wud/WUD.c b/src/revolution/wud/WUD.c index 9c38c36731..b6f7073699 100644 --- a/src/revolution/wud/WUD.c +++ b/src/revolution/wud/WUD.c @@ -1,34 +1,2844 @@ -#include <revolution/wud/WUD.h> +#include <revolution/wud.h> +#include <revolution/wud/__wud.h> +#include <cstddef> +#include <cstdio> +#include <cstring> +#include <mem.h> #include <revolution/os.h> -#include <revolution/wud/debug_msg.h> -#include "__wud.h" -#include "types.h" +#include <revolution/sc.h> +#include <revolution/wpad.h> +#include <revolution/wpad/bte.h> -wud_cb_st __rvl_wudcb; +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define CLAMP(val, min, max) ((val) > (max) ? (max) : (val) < (min) ? (min) : (val)) -static u16 _dev_handle_queue_size[WUD_MAX_DEV_ENTRY]; -static u16 _dev_handle_notack_num[WUD_MAX_DEV_ENTRY]; +#define DEBUGPrint WUD_DEBUGPrint + +#define BT_VSC_NINTENDO_INSTALL_PATCH 0xFC4F +#define BT_VSC_NINTENDO_WRITE_PATCH 0xFC4C + +void WUDSecurityCallback(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* pData); +void WUDSearchCallback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* pData); +void WUDVendorSpecificCallback(UINT8 len, UINT8* pData); +void WUDDeviceStatusCallback(tBTM_DEV_STATUS status); +void WUDStoredLinkKeyCallback(void* p1); +void WUDPowerManagerCallback(BD_ADDR addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hciStatus); + +//static void InitCore(void); + +static void WUDiRemovePatch(void); +static void WUDiWritePatch(void); +static void WUDiInstallPatch(void); + +#if SDK_AUG2010 +WUDControlBlock __rvl_wudcb; +#else +WUDControlBlock _wcb; +#endif +WUDDevInfo _work; +static WUDDiscResp _discResp; +SCBtDeviceInfoArray _scArray; +u8 __WUDHandlerStack[0x1000] ATTRIBUTE_ALIGN(32); + +extern u8 _scFlush; + +BD_ADDR_PTR _dev_handle_to_bda[WUD_MAX_DEV_ENTRY]; +u16 _dev_handle_queue_size[WUD_MAX_DEV_ENTRY]; +u16 _dev_handle_notack_num[WUD_MAX_DEV_ENTRY]; + +static BOOL _initialized = FALSE; +static u8 __bte_trace_level = 0; + +static OSAlarm _arm; + +static u8 _discNumResps; +static s8 _discRssi; + +// clang-format off +static u8 descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + + 0xA1, 0x01, // Collection (Application) + + 0x85, 0x10, // Report ID (16) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x11, // Report ID (17) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x12, // Report ID (18) + 0x95, 0x02, // Report Count (2) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x13, // Report ID (19) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x14, // Report ID (20) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x15, // Report ID (21) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x16, // Report ID (22) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x17, // Report ID (23) + 0x95, 0x06, // Report Count (6) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x18, // Report ID (24) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x19, // Report ID (25) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x1A, // Report ID (26) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x20, // Report ID (32) + 0x95, 0x06, // Report Count (6) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x21, // Report ID (33) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x22, // Report ID (34) + 0x95, 0x04, // Report Count (4) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x30, // Report ID (48) + 0x95, 0x02, // Report Count (2) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x31, // Report ID (49) + 0x95, 0x05, // Report Count (5) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x32, // Report ID (50) + 0x95, 0x0A, // Report Count (10) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x33, // Report ID (51) + 0x95, 0x11, // Report Count (17) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x34, // Report ID (52) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x35, // Report ID (53) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x36, // Report ID (54) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x37, // Report ID (55) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x3D, // Report ID (61) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x3E, // Report ID (62) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0x85, 0x3F, // Report ID (63) + 0x95, 0x15, // Report Count (21) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0xC0, // End Collection +}; +// clang-format on + +void* App_MEMalloc(u32 size) { + DEBUGPrint("App_MEMalloc\n"); + return _wcb.allocFunc(size); +} + +BOOL App_MEMfree(void* pBlock) { + DEBUGPrint("App_MEMfree\n"); + return _wcb.freeFunc(pBlock); +} + +static void ReverseAddr(BD_ADDR_PTR pDst, BD_ADDR src) { + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < BD_ADDR_LEN; i++) { + pDst[i] = src[BD_ADDR_LEN - 1 - i]; + } + + OSRestoreInterrupts(enabled); +} + +static void SyncFlushCallback(u32 status) { + WUDControlBlock* p = &_wcb; + + DEBUGPrint("SyncFlushCallback() : %d, Sync: %d\n", status, _wcb.syncState); + + if (p->syncState == WUD_STATE_SYNC_START) { + return; + } + + if (status == SC_STATUS_OK) { + p->syncState = WUD_STATE_SYNC_COMPLETE; + } else { + p->syncState = WUD_STATE_SYNC_ERROR; + } +} + +static void DeleteFlushCallback(u32 status) { + WUDControlBlock* p = &_wcb; + + DEBUGPrint("DeleteFlushCallback() : %d, Delete: %d\n", status, _wcb.deleteState); + + if (p->deleteState == WUD_STATE_DELETE_START) { + return; + } + + if (status == SC_STATUS_OK) { + p->deleteState = WUD_STATE_DELETE_DONE; + } else { + p->deleteState = WUD_STATE_DELETE_DONE; + } +} + +static void ShutFlushCallback(u32 status) { + WUDControlBlock* p = &_wcb; + + DEBUGPrint("ShutFlushCallback() : %d, Shutdown: %d\n", status, _wcb.shutdownState); + + OSCancelAlarm(&_wcb.alarm); + p->shutdownState = WUD_STATE_SHUTDOWN_DONE; + BTA_DisableBluetooth(); +} + +static void ClearDiscoverResult(void) { + _discNumResps = 0; + memset(&_discResp, 0, sizeof(WUDDiscResp)); +} + +static void _resumeSmpSync(OSAlarm* pAlarm, OSContext* pContext) { +#pragma unused(pAlarm) +#pragma unused(pContext) + + _wcb.syncState = WUD_STATE_SYNC_PREPARE_SEARCH; +} + +static void WUDiWaitForIncomingConnection(void) { + u32 waitSec = WUDiGetLinkNum() == WUD_MAX_CHANNELS - 1 ? 4 : 2; + + if (WUDiGetLinkNum() == WUD_MAX_CHANNELS && WUDiGetConnNumber() == WUD_MAX_CHANNELS) { + _wcb.syncState = WUD_STATE_SYNC_DONE; + } + + OSCreateAlarm(&_arm); + OSSetAlarm(&_arm, OSSecondsToTicks(waitSec), _resumeSmpSync); +} + +static u8 WUDiIsSyncDisabled(void) { + WUDControlBlock* p = &_wcb; + int i; + WUDDevInfo* pInfo; + u8 waitSecs; + + if (p->syncLoopNum == 0) { + return WUD_STATE_SYNC_DONE; + } + + if (WUDiGetLinkNum() == WUD_MAX_CHANNELS && WUDiGetConnNumber() == WUD_MAX_CHANNELS) { + return WUD_STATE_SYNC_DONE; + } + + if (p->syncSkipChecks) { + for (i = 0; i < WUD_MAX_DEV_ENTRY; i++) { + pInfo = WUDiGetDevInfoIndex(i); + + if (pInfo->status == 9) { + WUDSetSniffMode(pInfo->devAddr, 0); + return WUD_STATE_SYNC_PREPARE_SEARCH; + } + } + } + + if (p->syncLoopNum > 0) { + p->syncLoopNum--; + } + + if (p->syncLoopNum == -1) { + p->syncLoopNum = -2; + waitSecs = WUDiGetLinkNum() == 3 ? 4 : 2; + + if (WUDiGetLinkNum() == 4 && WUDiGetConnNumber() == 4) { + _wcb.syncState = WUD_STATE_SYNC_DONE; + } + + OSCreateAlarm(&_arm); + OSSetAlarm(&_arm, OSSecondsToTicks(waitSecs), _resumeSmpSync); + return 0x18U; + } + + return WUD_STATE_SYNC_START_SEARCH; +} + +static u8 WUDiStartSearch(void) { + WUDControlBlock* p = &_wcb; + tBTA_DM_INQ dm_inq; + + dm_inq.mode = BTM_LIMITED_INQUIRY; + dm_inq.max_resps = 1; + dm_inq.report_dup = FALSE; + + if (p->syncSkipChecks) { + dm_inq.duration = 5 - 2; + } else if (p->syncType == WUD_SYNC_TYPE_STANDARD) { + dm_inq.duration = WUDiGetLinkNum() == WUD_MAX_CHANNELS - 1 ? 10 : 5; + dm_inq.duration -= p->syncLoopNum; + } else { + dm_inq.duration = WUDiGetLinkNum() == WUD_MAX_CHANNELS - 1 ? 10 - 2 : 5 - 2; + } + + ClearDiscoverResult(); + BTA_DmSearch(&dm_inq, 0, &WUDSearchCallback); + + return WUD_STATE_SYNC_WAIT_FOR_SEARCH_RESULT; +} + +static u8 WUDiWaitForSearchResult(void) { + if (WUDiGetLinkNum() == WUD_MAX_CHANNELS && WUDiGetConnNumber() == WUD_MAX_CHANNELS) { + DEBUGPrint("Cancel searching because 4 connections exist.\n"); + BTA_DmSearchCancel(); + + return WUD_STATE_SYNC_CANCEL_SEARCH; + } + + return WUD_STATE_SYNC_WAIT_FOR_SEARCH_RESULT; +} + +static u8 WUDiNextStepBySearchResult(void) { + WUDControlBlock* p = &_wcb; + WUDSyncState nextState = WUD_STATE_SYNC_PREPARE_SEARCH; + + if (_discNumResps > 0) { + if (WUD_DEV_NAME_IS_CNT(_discResp.devName)) { + if (_discRssi > p->syncRssi) { + nextState = WUD_STATE_SYNC_IS_EXISTED_DEVICE; + } + } + } else { + WUDiWaitForIncomingConnection(); + nextState = WUD_STATE_SYNC_WAIT_FOR_INCOMING; + } + + return nextState; +} + +static u8 WUDiCheckDeviceDataBase(void) { + WUDDevInfo* pInfo; + WUDSyncState nextState = WUD_STATE_SYNC_PREPARE_FOR_UNKNOWN_DEVICE; + + pInfo = WUDiGetDevInfo(_discResp.devAddr); + + if (pInfo != NULL) { + memcpy(&_work, pInfo, sizeof(WUDDevInfo)); + nextState = WUD_STATE_SYNC_PREPARE_FOR_EXISTED_DEVICE; + } + + return nextState; +} + +static u8 WUDiExistedDevice(void) { + WUDDevInfo* pWork = &_work; + + pWork->status = 1; + + switch (pWork->sync_type) { + case 0: + case 2: + case 4: + case 5: { + if (_wcb.syncType == WUD_SYNC_TYPE_STANDARD) { + WUDiRemoveDevice(pWork->devAddr); + return WUD_STATE_SYNC_PREPARE_FOR_UNKNOWN_DEVICE; + } else { + pWork->sync_type = 4; + } + + break; + } + + case 1: + case 3: { + WUDiMoveBottomSmpDevInfoPtr(pWork); + WUDiRemoveDevice(_wcb.smpListTail->devInfo->devAddr); + return WUD_STATE_SYNC_PREPARE_FOR_UNKNOWN_DEVICE; + } + } + + return WUD_STATE_SYNC_TRY_CONNECT; +} + +static u8 WUDiUnknownDevice(void) { + WUDDevInfo* pWork = &_work; + + pWork->status = 1; + pWork->sync_type = _wcb.syncType == WUD_SYNC_TYPE_STANDARD ? 0 : 1; + + WUD_BDCPY(pWork->devAddr, _discResp.devAddr); + memcpy(pWork->conf.devName, _discResp.devName, sizeof(_discResp.devName)); + memset(pWork->linkKey, 0, LINK_KEY_LEN); + + return WUD_STATE_SYNC_TRY_CONNECT; +} + +static u8 WUDiTryConnecting(void) { + WUDSyncState nextState = WUD_STATE_SYNC_ERROR; + + if (WUD_DEV_NAME_IS_CNT(_discResp.devName)) { + _work.status = 2; + BTA_HhOpen(_work.devAddr, BTA_HH_PROTO_RPT_MODE, BTA_SEC_AUTHENTICATE); + nextState = WUD_STATE_SYNC_6; + } + + return nextState; +} + +static int WUDiSetPinCode(BD_ADDR addr) { + BD_ADDR pin; + BD_ADDR_PTR pAddr; + + pAddr = _wcb.syncType == WUD_SYNC_TYPE_STANDARD ? _wcb.hostAddr : addr; + + _work.UNK_0x5A = 1; + + ReverseAddr(pin, pAddr); + BTA_DmPinReply(addr, TRUE, BD_ADDR_LEN, pin); + + return 0; +} + +static BOOL WUDiIsFinishLinkKeyCmd(void) { + return _wcb.linkKeyState == WUD_STATE_LINK_KEY_START ? TRUE : FALSE; +} + +static BOOL WUDiIsFinishScCmd(void) { + return SCCheckStatus() != SC_STATUS_BUSY ? TRUE : FALSE; +} + +static WUDDevInfo* WUDiGetDevInfoFromIndex(s32 index) { + WUDDevInfo* result; + BOOL irq_enabled; + + irq_enabled = OSDisableInterrupts(); + + if (index >= 0 && index < WUD_MAX_DEV_ENTRY_FOR_STD) { + result = &_wcb.stdDevs[index]; + } else { + result = &_wcb.smpDevs[index - WUD_MAX_DEV_ENTRY_FOR_STD]; + } + + OSRestoreInterrupts(irq_enabled); + + return result; +} + +static u8 WUDiSaveDeviceToNand(void) { + WUDSyncState nextState = WUD_STATE_SYNC_COMPLETE; + WUDDevInfoList* pIt; + WUDDevInfo* devInfo; + u8 i; + u8 storedCount; + + if (!WUDiIsFinishScCmd()) { + return WUD_STATE_SYNC_STORED_DEV_INFO_TO_NAND; + } + + memset(&_scArray.regist, 0, sizeof(SCBtDeviceInfo) * WUD_MAX_DEV_ENTRY_FOR_STD); + + _scArray.num = WUDiGetDevNumber(); + + for (i = 0, storedCount = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + devInfo = WUDiGetDevInfoFromIndex(i); + if (devInfo->status != 0) { + if (devInfo->sync_type == 0 || devInfo->sync_type == 2 || devInfo->sync_type == 4) { + memcpy(&_scArray.regist[storedCount].addr, devInfo->devAddr, sizeof(BD_ADDR)); + memcpy(&_scArray.regist[storedCount].info, devInfo->conf.devName, sizeof(SCDevInfo)); + storedCount++; + } + } + } + + DEBUGPrint("%d devices is stored into SC.\n", storedCount); + + if (!SCSetBtDeviceInfoArray(&_scArray)) { + nextState = WUD_STATE_SYNC_STORED_DEV_INFO_TO_NAND; + } else { + nextState = WUD_STATE_SYNC_SC_FLUSH; + } + + return nextState; +} + +static void WUDiSaveFlush(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + + enabled = OSDisableInterrupts(); + p->syncState = WUD_STATE_SYNC_13; + OSRestoreInterrupts(enabled); + + SCFlushAsync(SyncFlushCallback); +} + +static u8 WUDiVirginSimpleSync(void) { + WUDDevInfo* pInfo; + + if (WUDiGetDevSmpNumber() == WUD_MAX_DEV_ENTRY_FOR_SMP) { + pInfo = WUDiGetRemoveSmpDevice(); + WUDiRemoveDevice(pInfo->devAddr); + } + + pInfo = WUDiGetNewDevInfo(); + memcpy(pInfo, &_work, sizeof(WUDDevInfo)); + + WUDiRegisterDevice(pInfo->devAddr); + WUDiMoveTopSmpDevInfoPtr(pInfo); + + _dev_handle_to_bda[pInfo->devHandle] = pInfo->devAddr; + + return WUD_STATE_SYNC_COMPLETE; +} + +static u8 WUDiVirginStandardSync(void) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + + if (WUDiGetDevNumber() == WUD_MAX_DEV_ENTRY_FOR_STD) { + p->linkKeyState = 1; + BTM_ReadStoredLinkKey(0, WUDStoredLinkKeyCallback); + + return WUD_STATE_SYNC_WAIT_FOR_READING; + } else { + pInfo = WUDiGetNewDevInfo(); + memcpy(pInfo, &_work, sizeof(WUDDevInfo)); + + WUDiRegisterDevice(pInfo->devAddr); + + _dev_handle_to_bda[pInfo->devHandle] = pInfo->devAddr; + + return WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM; + } + +} + +static u8 WUDiChangeSimpleToStandard(void) { + WUDiMoveBottomSmpDevInfoPtr(&_work); + WUDiRemoveDevice(_wcb.smpListTail->devInfo->devAddr); + return WUDiVirginStandardSync(); +} + +static u8 WUDiRegisterSyncDevice(void) { + WUDSyncState nextState; + + switch (_work.sync_type) { + case 1: { + nextState = WUD_STATE_SYNC_VIRGIN_SIMPLE; + break; + } + + case 0: { + nextState = WUD_STATE_SYNC_VIRGIN_STANDARD; + break; + } + + case 5: { + nextState = WUD_STATE_SYNC_CHANGE_SIMPLE_TO_STANDARD; + break; + } + + case 3: { + nextState = WUD_STATE_SYNC_COMPLETE; + break; + } + + case 4: { + nextState = WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM; + break; + } + + case 2: { + nextState = WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM; + break; + } + + default: { + // UB + break; + } + } + + return nextState; +} + +static u8 WUDiStoredLinkKey(void) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + + if (!WUDiIsFinishLinkKeyCmd()) { + return WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM; + } + + pInfo = WUDiGetDevInfo(_work.devAddr); + + // clang-format off + DEBUGPrint("write stored link key\n"); + + DEBUGPrint("addr : %02x:%02x:%02x:%02x:%02x:%02x\n", + pInfo->devAddr[0], pInfo->devAddr[1], pInfo->devAddr[2], + pInfo->devAddr[3], pInfo->devAddr[4], pInfo->devAddr[5]); + + DEBUGPrint("key : %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + pInfo->linkKey[0], pInfo->linkKey[1], pInfo->linkKey[2], pInfo->linkKey[3], + pInfo->linkKey[4], pInfo->linkKey[5], pInfo->linkKey[6], pInfo->linkKey[7], + pInfo->linkKey[8], pInfo->linkKey[9], pInfo->linkKey[10], pInfo->linkKey[11], + pInfo->linkKey[12], pInfo->linkKey[13], pInfo->linkKey[14], pInfo->linkKey[15]); + // clang-format on + + p->linkKeyState = WUD_STATE_LINK_KEY_WRITING; + + BTM_WriteStoredLinkKey(1, &pInfo->devAddr, &pInfo->linkKey, WUDStoredLinkKeyCallback); + + return WUD_STATE_SYNC_WAIT_FOR_STORING; +} + +static u8 WUDiWaitFinishStoring(void) { + return WUDiIsFinishLinkKeyCmd() ? WUD_STATE_SYNC_STORED_DEV_INFO_TO_NAND : WUD_STATE_SYNC_WAIT_FOR_STORING; +} + +static u8 WUDiWaitFinishReading(void) { + WUDSyncState nextState = WUD_STATE_SYNC_WAIT_FOR_READING; + + if (WUDiIsFinishLinkKeyCmd()) { + nextState = WUD_STATE_SYNC_VIRGIN_STANDARD; + WUDiRemoveDevice(_wcb.pairAddr); + } + + return nextState; +} + +static u8 WUDiSyncComplete(void) { + _wcb.syncedNum++; + + memset(&_work, 0, sizeof(WUDDevInfo)); + + return _wcb.syncType == WUD_SYNC_TYPE_STANDARD ? WUD_STATE_SYNC_DONE : WUD_STATE_SYNC_PREPARE_SEARCH; +} + +static u8 WUDiSyncError(void) { + memset(&_work, 0, sizeof(WUDDevInfo)); + + return _wcb.syncType == WUD_SYNC_TYPE_STANDARD ? WUD_STATE_SYNC_DONE : WUD_STATE_SYNC_PREPARE_SEARCH; +} + +static u8 WUDiSyncDone(void) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + int i; + WUDSyncDeviceCallback pSyncCallback; + + if (p->syncSkipChecks) { + for (i = 0; i < WUD_MAX_DEV_ENTRY; i++) { + pInfo = WUDiGetDevInfoIndex(i); + + if (pInfo->status == 8) { + WUDSetSniffMode(pInfo->devAddr, 8); + return WUD_STATE_SYNC_DONE; + } + } + } + + OSCancelAlarm(&p->alarm); + + pSyncCallback = p->syncType == WUD_SYNC_TYPE_STANDARD ? p->syncStdCB : p->syncSmpCB; + + if (pSyncCallback != NULL) { + pSyncCallback(WUD_RESULT_SYNC_DONE, p->syncedNum); + } + + DEBUGPrint("Pairing Done\n"); + return WUD_STATE_SYNC_START; +} + +static void SyncHandler(void) { + WUDControlBlock* p = &_wcb; + + switch (p->syncState) { + case WUD_STATE_SYNC_PREPARE_SEARCH: { + p->syncState = WUDiIsSyncDisabled(); + break; + } + + case WUD_STATE_SYNC_START_SEARCH: { + p->syncState = WUDiStartSearch(); + break; + } + + case WUD_STATE_SYNC_CHECK_SEARCH_RESULT: { + p->syncState = WUDiNextStepBySearchResult(); + break; + } + + case WUD_STATE_SYNC_IS_EXISTED_DEVICE: { + p->syncState = WUDiCheckDeviceDataBase(); + break; + } + + case WUD_STATE_SYNC_PREPARE_FOR_EXISTED_DEVICE: { + p->syncState = WUDiExistedDevice(); + break; + } + + case WUD_STATE_SYNC_PREPARE_FOR_UNKNOWN_DEVICE: { + p->syncState = WUDiUnknownDevice(); + break; + } + + case WUD_STATE_SYNC_TRY_CONNECT: { + p->syncState = WUDiTryConnecting(); + break; + } + + case WUD_STATE_SYNC_REGISTER_DEVICE: { + p->syncState = WUDiRegisterSyncDevice(); + break; + } + + case WUD_STATE_SYNC_VIRGIN_SIMPLE: { + p->syncState = WUDiVirginSimpleSync(); + break; + } + + case WUD_STATE_SYNC_VIRGIN_STANDARD: { + p->syncState = WUDiVirginStandardSync(); + break; + } + + case WUD_STATE_SYNC_CHANGE_SIMPLE_TO_STANDARD: { + p->syncState = WUDiChangeSimpleToStandard(); + break; + } + + case WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM: { + p->syncState = WUDiStoredLinkKey(); + break; + } + + case WUD_STATE_SYNC_WAIT_FOR_STORING: { + p->syncState = WUDiWaitFinishStoring(); + break; + } + + case WUD_STATE_SYNC_STORED_DEV_INFO_TO_NAND: { + p->syncState = WUDiSaveDeviceToNand(); + break; + } + + case WUD_STATE_SYNC_SC_FLUSH: { + WUDiSaveFlush(); + break; + } + + case WUD_STATE_SYNC_WAIT_FOR_READING: { + p->syncState = WUDiWaitFinishReading(); + break; + } + + case WUD_STATE_SYNC_COMPLETE: { + p->syncState = WUDiSyncComplete(); + break; + } + + case WUD_STATE_SYNC_ERROR: { + p->syncState = WUDiSyncError(); + break; + } + + case WUD_STATE_SYNC_DONE: { + p->syncState = WUDiSyncDone(); + break; + } + + case WUD_STATE_SYNC_WAIT_FOR_SEARCH_RESULT: { + p->syncState = WUDiWaitForSearchResult(); + break; + } + + case WUD_STATE_SYNC_6: + case WUD_STATE_SYNC_13: + case WUD_STATE_SYNC_WAIT_FOR_INCOMING: + case WUD_STATE_SYNC_CANCEL_SEARCH: { + break; + } + + case WUD_STATE_SYNC_11: + case WUD_STATE_SYNC_12: + default: { + DEBUGPrint("WARNING: Illigal status\n"); + break; + } + } +} + +static void SyncHandler0(OSAlarm* pAlarm, OSContext* pContext) { + OSSwitchFiberEx((u32)pAlarm, (u32)pContext, 0, 0, (u32)SyncHandler, (u32)__WUDHandlerStack + sizeof(__WUDHandlerStack)); +} + +static WUDDeleteState WUDiDisallowIncoming(void) { + BTA_DmSetVisibility(FALSE, FALSE); + return WUD_STATE_DELETE_DISCONNECT_ALL; +} + +static WUDDeleteState WUDiTerminateDevice(void) { + int i; + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + pInfo = &p->stdDevs[i]; + + if (pInfo->status > 1) { + btm_remove_acl(pInfo->devAddr); + } + } + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + pInfo = &p->smpDevs[i]; + + if (pInfo->status > 1) { + btm_remove_acl(pInfo->devAddr); + } + } + + return WUD_STATE_DELETE_CLEANUP_DATABASE; +} + +static WUDDeleteState WUDiDeleteDevice(void) { + int i; + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + + if (WUDiGetLinkNum() > 0) { + return WUD_STATE_DELETE_CLEANUP_DATABASE; + } + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + pInfo = &p->stdDevs[i]; + + if (pInfo->status == 1) { + WUDiRemoveDevice(pInfo->devAddr); + } + } + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + pInfo = &p->smpDevs[i]; + + if (pInfo->status == 1) { + WUDiRemoveDevice(pInfo->devAddr); + } + } + + return WUD_STATE_DELETE_CLEANUP_SETTING; +} + +static void WUDiCleanUp(void) { + WUDControlBlock* p = &_wcb; + BOOL success = FALSE; + + if (SCCheckStatus() != SC_STATUS_OK) { + return; + } + + memset(&_scArray, 0, sizeof(SCBtDeviceInfoArray)); + success |= SCSetBtDeviceInfoArray(&_scArray); + + if (success) { + p->deleteState = WUD_STATE_DELETE_6; + SCFlushAsync(DeleteFlushCallback); + } +} + +static WUDDeleteState WUDiDeleteAllComplete(void) { + WUDControlBlock* p = &_wcb; + + WUDSetVisibility(FALSE, WUDGetConnectable()); + + OSCancelAlarm(&p->alarm); + p->deleteState = WUD_STATE_DELETE_START; + + if (p->clearDevCB != NULL) { + p->clearDevCB(WUD_RESULT_DELETE_COMPLETE); + } + + return WUD_STATE_DELETE_START; +} + +static void DeleteAllHandler(void) { + WUDControlBlock* p = &_wcb; + + p->syncState = WUD_STATE_SYNC_START; + + switch (p->deleteState) { + case WUD_STATE_DELETE_DISALLOW_INCOMING: { + p->deleteState = WUDiDisallowIncoming(); + break; + } + + case WUD_STATE_DELETE_DISCONNECT_ALL: { + p->deleteState = WUDiTerminateDevice(); + break; + } + + case WUD_STATE_DELETE_CLEANUP_DATABASE: { + p->deleteState = WUDiDeleteDevice(); + break; + } + + case WUD_STATE_DELETE_CLEANUP_SETTING: { + WUDiCleanUp(); + break; + } + + case WUD_STATE_DELETE_DONE: { + p->deleteState = WUDiDeleteAllComplete(); + break; + } + + case WUD_STATE_DELETE_7: { + break; + } + } +} + +static void DeleteAllHandler0(OSAlarm* pAlarm, OSContext* pContext) { + OSSwitchFiberEx((u32)pAlarm, (u32)pContext, 0, 0, (u32)DeleteAllHandler, (u32)__WUDHandlerStack + sizeof(__WUDHandlerStack)); +} + +static WUDStackState WUDiCheckRegisteredDeviceInfo(void) { + WUDControlBlock* p = &_wcb; + + // Set by BTA_HH_ENABLE_EVT + if (p->hhFlags == 1) { + p->linkKeyState = WUD_STATE_LINK_KEY_READING; + BTM_ReadStoredLinkKey(NULL, WUDStoredLinkKeyCallback); + } + + return WUD_STATE_STACK_CHECK_DEVICE_INFO; +} + +static WUDStackState WUDiClearUnregisteredDevice(void) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + int i; + + if (p->linkKeyState == WUD_STATE_LINK_KEY_START) { + for (i = 0; i < WUD_MAX_DEV_ENTRY; i++) { + pInfo = WUDiGetDevInfoIndex(i); + if (pInfo->status == 0) { + continue; + } + + if (pInfo->UNK_0x5C == 1) { + p->linkKeyState = WUD_STATE_LINK_KEY_DELETING; + BTM_DeleteStoredLinkKey(pInfo->devAddr, WUDStoredLinkKeyCallback); + + pInfo->UNK_0x5C = 0; + return WUD_STATE_STACK_CHECK_DEVICE_INFO; + } + + if (pInfo->UNK_0x5C != 3) { + WUDiRemoveDevInfo(pInfo->devAddr); + } + } + + return WUD_STATE_STACK_DONE; + } + + return WUD_STATE_STACK_CHECK_DEVICE_INFO; +} + +static WUDStackState WUDiStackSetupComplete(void) { + WUDControlBlock* p = &_wcb; + + if (p->linkKeyState == WUD_STATE_LINK_KEY_START) { + OSCancelAlarm(&p->alarm); + WUDiGetFirmwareVersion(); + return WUD_STATE_STACK_INITIALIZED; + } + + return WUD_STATE_STACK_CHECK_DEVICE_INFO; +} + +static void EnableStackHandler(void) { + WUDControlBlock* p = &_wcb; + + switch (p->stackState) { + case WUD_STATE_STACK_GET_STORED_LINK_KEY: { + p->stackState = WUDiCheckRegisteredDeviceInfo(); + break; + } + + case WUD_STATE_STACK_CHECK_DEVICE_INFO: { + p->stackState = WUDiClearUnregisteredDevice(); + break; + } + + case WUD_STATE_STACK_DONE: { + p->stackState = WUDiStackSetupComplete(); + break; + } + } +} + +static void EnableStackHandler0(OSAlarm* pAlarm, OSContext* pContext) { + OSSwitchFiberEx((u32)pAlarm, (u32)pContext, 0, 0, (u32)EnableStackHandler, (u32)__WUDHandlerStack + sizeof(__WUDHandlerStack)); +} + +static WUDInitState WUDiWaitSCSetup(void) { + //TODO: probably a fakematch + return (SCCheckStatus() == SC_STATUS_OK) + 1; +} + +static WUDInitState WUDiGetRegisteredDevice(void) { + int i; + WUDDevInfo* pInfo; + + memset(&_scArray, 0, sizeof _scArray); + SCGetBtDeviceInfoArray(&_scArray); + + for (i = 0; i < _scArray.num; i++) { + pInfo = WUDiGetNewDevInfo(); + + WUD_BDCPY(pInfo->devAddr, _scArray.regist[i].addr); + + memcpy(&pInfo->conf, &_scArray.regist[i].info, sizeof(SCDevInfo)); + + pInfo->status = 1; + pInfo->sync_type = 0; + pInfo->UNK_0x5C = 2; + + if (WUD_DEV_NAME_IS_CNT_01(pInfo->conf.devName)) { + pInfo->subclass = 2; // subclass 2 is marked as reserved + + pInfo->hhAttrMask = BTA_HH_SEC_REQUIRED | BTA_HH_BATTERY_POWER | BTA_HH_REMOTE_WAKE | BTA_HH_SUP_TOUT_AVLBL | BTA_HH_RECONN_INIT; + + pInfo->appID = 3; + } + + DEBUGPrint("addr : %02x:%02x:%02x:%02x:%02x:%02x\n", pInfo->devAddr[0], pInfo->devAddr[1], pInfo->devAddr[2], pInfo->devAddr[3], + pInfo->devAddr[4], pInfo->devAddr[5]); + + DEBUGPrint("name : %s\n", pInfo->conf.devName); + } + + return WUD_STATE_INIT_DONE; +} + +static WUDInitState WUDiInitComplete(void) { + WUDControlBlock* p = &_wcb; + + OSCancelAlarm(&p->alarm); + p->libStatus = WUD_LIB_STATUS_1; + + BTA_EnableBluetooth(WUDSecurityCallback); + return WUD_STATE_INIT_INITIALIZED; +} + +static void InitHandler(void) { + WUDControlBlock* p = &_wcb; + + switch (p->initState) { + case WUD_STATE_INIT_WAIT_FOR_INITIALIZATION: { + p->initState = WUDiWaitSCSetup(); + break; + } + + case WUD_STATE_INIT_GET_DEV_INFO: { + p->initState = WUDiGetRegisteredDevice(); + break; + } + + case WUD_STATE_INIT_DONE: { + p->initState = WUDiInitComplete(); + break; + } + } +} + +static void InitHandler0(OSAlarm* pAlarm, OSContext* pContext) { + OSSwitchFiberEx((u32)pAlarm, (u32)pContext, 0, 0, (u32)InitHandler, (u32)__WUDHandlerStack + sizeof(__WUDHandlerStack)); +} + +static void WUDiContMapTableFlush(void) { + WUDControlBlock* p = &_wcb; + u8 nextState; + + if (SCCheckStatus() == SC_STATUS_OK && SCSetBtDeviceInfoArray(&_scArray)) { + SCFlushAsync(ShutFlushCallback); + nextState = WUD_STATE_SHUTDOWN_FLUSH_SETTINGS; + } else { + nextState = WUD_STATE_SHUTDOWN_STORE_SETTINGS; + } + + p->shutdownState = nextState; +} + +static void ShutdownHandler(void) { + WUDControlBlock* p = &_wcb; + + switch (p->shutdownState) { + case WUD_STATE_SHUTDOWN_STORE_SETTINGS: { + WUDiContMapTableFlush(); + break; + } + + case WUD_STATE_SHUTDOWN_FLUSH_SETTINGS: { + break; + } + } +} + +static void ShutdownHandler0(OSAlarm* pAlarm, OSContext* pContext) { + OSSwitchFiberEx((u32)pAlarm, (u32)pContext, 0, 0, (u32)ShutdownHandler, (u32)__WUDHandlerStack + sizeof(__WUDHandlerStack)); +} + +BOOL WUDInit(void) { + WUDControlBlock* p = &_wcb; + BOOL irqEnabled; + int i; + + if (_initialized) { + return FALSE; + } + + irqEnabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY; i++) { + _dev_handle_to_bda[i] = NULL; + _dev_handle_queue_size[i] = 0; + _dev_handle_notack_num[i] = 0; + } + + p->smpListTail = &p->smpList[WUD_MAX_DEV_ENTRY_FOR_SMP - 1]; + p->smpListHead = &p->smpList[0]; + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + p->smpList[i].devInfo = &p->smpDevs[WUD_MAX_DEV_ENTRY_FOR_SMP - 1 - i]; + p->smpList[i].prev = i == 0 ? NULL : &p->smpList[i - 1]; + p->smpList[i].next = i == WUD_MAX_DEV_ENTRY_FOR_SMP - 1 ? NULL : &p->smpList[i + 1]; + } + + p->syncStdCB = NULL; + p->syncSmpCB = NULL; + p->clearDevCB = NULL; + p->hidConnCB = NULL; + p->hidRecvCB = NULL; + + p->syncState = WUD_STATE_SYNC_START; + p->linkKeyState = WUD_STATE_LINK_KEY_START; + p->deleteState = WUD_STATE_DELETE_START; + p->stackState = WUD_STATE_STACK_START; + p->initState = WUD_STATE_INIT_START; + p->shutdownState = WUD_STATE_SHUTDOWN_START; + + p->syncSkipChecks = FALSE; + p->syncType = WUD_SYNC_TYPE_STANDARD; + p->syncLoopNum = 1; + + p->connectable = FALSE; + p->discoverable = FALSE; + + p->libStatus = WUD_LIB_STATUS_0; + p->pmID = 0; + p->syncRssi = -65; + + memset(p->hostAddr, 0, BD_ADDR_LEN); + memset(p->pairAddr, 0, BD_ADDR_LEN); + + p->bufferStatus0 = 0; + p->bufferStatus1 = 10; + + WUDiClearDevice(); + + p->initState = WUD_STATE_INIT_WAIT_FOR_INITIALIZATION; + + OSRestoreInterrupts(irqEnabled); + + DEBUGPrint("BTA_Init() is started\n"); + + BTA_Init(); + bta_sys_set_trace_level(__bte_trace_level); + L2CA_SetTraceLevel(__bte_trace_level); + SDP_SetTraceLevel(__bte_trace_level); + + DEBUGPrint("BTA_Init() is done\n"); + + SCInit(); + + OSCreateAlarm(&p->alarm); + OSSetPeriodicAlarm(&p->alarm, __OSGetSystemTime(), OSMillisecondsToTicks(10), InitHandler0); + + _initialized = TRUE; + return TRUE; +} + +void WUDRegisterAllocator(WUDAllocFunc pAllocFunc, WUDFreeFunc pFreeFunc) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + p->allocFunc = pAllocFunc; + p->freeFunc = pFreeFunc; + + OSRestoreInterrupts(enabled); +} + +extern u32 __ntd_get_allocated_mem_size(void); + +u32 WUDGetAllocatedMemSize(void) { + return __ntd_get_allocated_mem_size(); +} + +void WUDShutdown(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + WUDDevInfoList* pIt; + + DEBUGPrint("WUDShutdown()\n"); + + WUDSetVisibility(FALSE, FALSE); + + enabled = OSDisableInterrupts(); + + if (WUDIsBusy()) { + OSCancelAlarm(&p->alarm); + } + + p->shutdownState = WUD_STATE_SHUTDOWN_STORE_SETTINGS; + + OSCreateAlarm(&p->alarm); + OSSetPeriodicAlarm(&p->alarm, __OSGetSystemTime(), OSMillisecondsToTicks(10), ShutdownHandler0); + + p->libStatus = WUD_LIB_STATUS_4; + + OSRestoreInterrupts(enabled); +} + +WUDLibStatus WUDGetStatus(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + s8 libStatus = p->libStatus; + + OSRestoreInterrupts(enabled); + return libStatus; +} u8 WUDGetBufferStatus(void) { - wud_cb_st* p_wcb = &__rvl_wudcb; - u8 ret; - BOOL intrStatus = OSDisableInterrupts(); + WUDControlBlock* p = &_wcb; + u8 status; + BOOL enabled = OSDisableInterrupts(); - ret = p_wcb->bufferStatus1 - p_wcb->bufferStatus0; + status = p->bufferStatus1 - p->bufferStatus0; - OSRestoreInterrupts(intrStatus); - return ret; + OSRestoreInterrupts(enabled); + return status; +} + +void WUDSetSniffMode(BD_ADDR addr, s32 interval) { + WUDControlBlock* p = &_wcb; + tBTM_PM_PWR_MD block; + + if (interval > 0) { + block.mode = BTM_PM_MD_SNIFF; + } else { + block.mode = BTM_PM_MD_ACTIVE; + } + + block.max = interval; + block.min = interval; + block.attempt = 1; + block.timeout = 0; + + BTM_SetPowerMode(p->pmID, addr, &block); +} + +WUDSyncDeviceCallback WUDSetSyncSimpleCallback(WUDSyncDeviceCallback pCallback) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + WUDSyncDeviceCallback pOldCallback; + + DEBUGPrint("WUDSetSyncDeviceCallback\n"); + + enabled = OSDisableInterrupts(); + + pOldCallback = p->syncSmpCB; + p->syncSmpCB = pCallback; + + OSRestoreInterrupts(enabled); + return pOldCallback; +} + +WUDClearDeviceCallback WUDSetClearDeviceCallback(WUDClearDeviceCallback pCallback) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + WUDClearDeviceCallback pOldCallback; + + DEBUGPrint("WUDSetClearDeviceCallback\n"); + + enabled = OSDisableInterrupts(); + + pOldCallback = p->clearDevCB; + p->clearDevCB = pCallback; + + OSRestoreInterrupts(enabled); + return pOldCallback; +} + +static BOOL StartSyncDevice(u8 syncType, s8 syncLoopNum, BOOL syncSkipChecks) { + WUDControlBlock* p = &_wcb; + BOOL success = FALSE; + BOOL enabled; + u32 libStatus; + + enabled = OSDisableInterrupts(); + libStatus = p->libStatus; + OSRestoreInterrupts(enabled); + + if (libStatus == WUD_LIB_STATUS_3 && !WUDIsBusy()) { + enabled = OSDisableInterrupts(); + + p->syncState = WUD_STATE_SYNC_PREPARE_SEARCH; + p->syncLoopNum = syncLoopNum; + p->syncType = syncType; + p->syncSkipChecks = syncSkipChecks ? TRUE : FALSE; + p->syncedNum = 0; + + OSCreateAlarm(&p->alarm); + OSSetPeriodicAlarm(&p->alarm, __OSGetSystemTime(), OSMillisecondsToTicks(20), SyncHandler0); + + OSRestoreInterrupts(enabled); + + success = TRUE; + } + + return success; +} + +static BOOL StartSyncStandard(BOOL syncSkipChecks) { + return StartSyncDevice(WUD_SYNC_TYPE_STANDARD, 3, syncSkipChecks); +} + +BOOL WUDStartSyncDevice(void) { + WUDControlBlock* p = &_wcb; + BOOL success; + BOOL enabled; + WUDSyncDeviceCallback pSyncCallback; + + DEBUGPrint("WUDStartSyncDevice()\n"); + success = StartSyncStandard(FALSE); + + enabled = OSDisableInterrupts(); + pSyncCallback = p->syncStdCB; + OSRestoreInterrupts(enabled); + + if (!success && pSyncCallback != NULL) { + pSyncCallback(WUD_RESULT_SYNC_BUSY, 0); + } + + return success; +} + +static BOOL StartSyncSimple(BOOL syncSkipChecks) { + return StartSyncDevice(WUD_SYNC_TYPE_SIMPLE, -1, syncSkipChecks); +} + +BOOL WUDStartFastSyncSimple(void) { + WUDControlBlock* p = &_wcb; + BOOL success; + BOOL enabled; + WUDSyncDeviceCallback pSyncCallback; + + DEBUGPrint("WUDStartSyncSimple()\n"); + success = StartSyncSimple(TRUE); + + enabled = OSDisableInterrupts(); + pSyncCallback = p->syncSmpCB; + OSRestoreInterrupts(enabled); + + if (!success && pSyncCallback != NULL) { + pSyncCallback(WUD_RESULT_SYNC_BUSY, 0); + } + + return success; +} + +BOOL WUDStartSyncSimple(void) { + WUDControlBlock* p = &_wcb; + BOOL success; + BOOL enabled; + WUDSyncDeviceCallback pSyncCallback; + + DEBUGPrint("WUDStartSyncSimple()\n"); + success = StartSyncSimple(FALSE); + + enabled = OSDisableInterrupts(); + pSyncCallback = p->syncSmpCB; + OSRestoreInterrupts(enabled); + + if (!success && pSyncCallback != NULL) { + pSyncCallback(WUD_RESULT_SYNC_BUSY, 0); + } + + return success; +} + +BOOL WUDCancelSyncDevice(void) { + DEBUGPrint("WUDCancelSyncDevice()\n"); +} + +static BOOL StopSync(void) { + WUDControlBlock* p; + BOOL success; + BOOL enabled; + + DEBUGPrint("WUDStopSyncSimple()\n"); + + p = &_wcb; + success = FALSE; + enabled = OSDisableInterrupts(); + + if (p->libStatus == WUD_LIB_STATUS_3) { + if (p->syncState == WUD_STATE_SYNC_WAIT_FOR_SEARCH_RESULT) { + BTA_DmSearchCancel(); + } + + p->syncLoopNum = 0; + + success = TRUE; + } + + OSRestoreInterrupts(enabled); + return success; +} + +BOOL WUDStopSyncSimple(void) { + return StopSync(); +} + +BOOL WUDStartClearDevice(void) { + WUDControlBlock* p = &_wcb; + BOOL success; + BOOL enabled; + u32 libStatus; + + success = FALSE; + DEBUGPrint("WUDStartClearDevice()\n"); + + enabled = OSDisableInterrupts(); + libStatus = p->libStatus; + + OSRestoreInterrupts(enabled); + + if (libStatus == WUD_LIB_STATUS_3 && !WUDIsBusy()) { + enabled = OSDisableInterrupts(); + + p->deleteState = WUD_STATE_DELETE_DISALLOW_INCOMING; + + OSCreateAlarm(&p->alarm); + OSSetPeriodicAlarm(&p->alarm, __OSGetSystemTime(), OSMillisecondsToTicks(20), DeleteAllHandler0); + + OSRestoreInterrupts(enabled); + + success = TRUE; + } + + return success; +} + +BOOL WUDSetDisableChannel(s8 afhChannel) { + int first = 0; + int last = 0; + BOOL success = FALSE; + WUDControlBlock* p = &_wcb; + BOOL enabled; + u32 libStatus; + tBTM_STATUS status; + + DEBUGPrint("WUDSetDisableChannel()\n"); + + if (afhChannel < 0 || 13 < afhChannel) { + return FALSE; + } + + enabled = OSDisableInterrupts(); + libStatus = p->libStatus; + OSRestoreInterrupts(enabled); + + if (libStatus == WUD_LIB_STATUS_3) { + if (!afhChannel) { + first = 0xFF; + last = 0xFF; + } else { + first = (afhChannel + 1) * 5 - 14; + last = (afhChannel + 1) * 5 + 14; + + if (first < 0) { + first = 0; + } + + if (last > 78) { + last = 78; + } + } + + status = BTM_SetAfhChannels(first, last); + DEBUGPrint("BTM_SetAfhChannels() : %d\n", status); + + success = TRUE; + } + + return success; +} + +WUDHidRecvCallback WUDSetHidRecvCallback(WUDHidRecvCallback pCallback) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + WUDHidRecvCallback pOldCallback; + + DEBUGPrint("WUDSetHidRecvCallback()\n"); + + enabled = OSDisableInterrupts(); + + pOldCallback = p->hidRecvCB; + p->hidRecvCB = pCallback; + + OSRestoreInterrupts(enabled); + return pOldCallback; +} + +WUDHidConnCallback WUDSetHidConnCallback(WUDHidConnCallback pCallback) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + WUDHidConnCallback pOldCallback; + + DEBUGPrint("WUDSetHidConnCallback()\n"); + + enabled = OSDisableInterrupts(); + + pOldCallback = p->hidConnCB; + p->hidConnCB = pCallback; + + OSRestoreInterrupts(enabled); + return pOldCallback; +} + +void WUDSetVisibility(u8 disc, u8 conn) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + p->discoverable = disc; + p->connectable = conn; + + OSRestoreInterrupts(enabled); + BTA_DmSetVisibility(disc, conn); +} + +u8 WUDGetConnectable(void) { + WUDControlBlock* p = &_wcb; + u8 connectable; + BOOL enabled = OSDisableInterrupts(); + + connectable = p->connectable; + + OSRestoreInterrupts(enabled); + return connectable; +} + +void reset_again_cb(void* p1) { +#pragma unused(p1) + + WUDiInitSub(); +} + +void reset_again(void) { + BTM_DeviceReset(reset_again_cb); +} + +// clang-format off +static u8 patch_binary[] = { + 0x70, 0x99, 0x08, 0x00, // address (little-endian) + 0x38, 0x00, 0x00, 0x00, // size (little-endian) + + // patch data + 0x88, 0x43, 0xD1, 0x07, + 0x09, 0x0C, 0x08, 0x43, + 0xA0, 0x62, 0x19, 0x23, + 0xDB, 0x01, 0x33, 0x80, + 0x7C, 0xF7, 0x88, 0xF8, + 0x28, 0x76, 0x80, 0xF7, + 0x17, 0xFF, 0x43, 0x78, + 0xEB, 0x70, 0x19, 0x23, + 0xDB, 0x01, 0x33, 0x87, + 0x7C, 0xF7, 0xBC, 0xFB, + 0x0B, 0x60, 0xA3, 0x7B, + 0x01, 0x49, 0x0B, 0x60, + 0x90, 0xF7, 0x96, 0xFB, + 0xD8, 0x1D, 0x08, 0x00, +}; +// clang-format on + +// clang-format off +static WUDPatchList patch_install = { + 5, + { + {0x20, 0xBC, 0x65, 0x01, 0x00, 0x84, 0x42, 0x09, 0xD2, 0x84, 0x42, 0x09, 0xD1}, + {0x21, 0x84, 0x5A, 0x00, 0x00, 0x83, 0xF0, 0x74, 0xFF, 0x09, 0x0C, 0x08, 0x43}, + {0x22, 0x00, 0x61, 0x00, 0x00, 0x83, 0xF0, 0x40, 0xFC, 0x00, 0x00, 0x00, 0x00}, + {0x23, 0xCC, 0x9F, 0x01, 0x00, 0x6F, 0xF0, 0xE4, 0xFC, 0x03, 0x28, 0x7D, 0xD1}, + {0x24, 0x3C, 0x62, 0x01, 0x00, 0x28, 0x20, 0x00, 0xE0, 0x60, 0x8D, 0x23, 0x68}, + } +}; +// clang-format on + +static u8 remove_patch[] = {0x00}; + +static u8 install_num = 0; +static u8 patch_num = 0; + +static u32 addr = 0; +static s32 offset = 0; +static u32 size = 0; + +static void remove_patch_cb(tBTM_VSC_CMPL* p1) { + if (p1 == NULL) { + WUDiInitSub(); + } else { + offset = 0; + WUDiWritePatch(); + } +} + +static void WUDiRemovePatch(void) { + BTM_VendorSpecificCommand(BT_VSC_NINTENDO_INSTALL_PATCH, sizeof(remove_patch), remove_patch, remove_patch_cb); +} + +static void write_patch_cb(tBTM_VSC_CMPL* p1) { + if (p1 != NULL) { + if (size == (u32)offset) { + install_num = 0; + patch_num = patch_install.num; + WUDiInstallPatch(); + } else { + WUDiWritePatch(); + } + } else { + WUDiInitSub(); + } +} + +static void WUDiWritePatch(void) { + u8 buf[WUD_PATCH_BUFFER_SIZE]; + u8 length; + int i; + + length = MIN(size - offset, WUD_PATCH_BUFFER_SIZE - sizeof(u32)); + + for (i = 0; i < (s32)sizeof(u32); i++) { + buf[i] = (addr + offset) >> i * 8; + } + + for (i = 0; i < (s32)length; i++) { + buf[(s32)sizeof(u32) + i] = patch_binary[sizeof(size) + sizeof(offset) + offset + i]; + } + + offset += length; + BTM_VendorSpecificCommand(BT_VSC_NINTENDO_WRITE_PATCH, (s32)sizeof(u32) + length, buf, write_patch_cb); +} + +static void install_patch_cb(tBTM_VSC_CMPL* p1) { + if (p1 != NULL) { + if (patch_num == install_num) { + WUDiInitSub(); + } else { + WUDiInstallPatch(); + } + } else { + WUDiInitSub(); + } +} + +static void WUDiInstallPatch(void) { + u8 buf[WUD_PATCH_BUFFER_SIZE]; + u8 num; + + num = MIN(patch_num - install_num, WUD_MAX_PATCHES); + buf[offsetof(WUDPatchList, num)] = num; + + memcpy(&buf[offsetof(WUDPatchList, cmds)], patch_install.cmds[install_num].data, num * sizeof(WUDPatchCmd)); + + install_num += num; + BTM_VendorSpecificCommand(BT_VSC_NINTENDO_INSTALL_PATCH, sizeof(num) + num * sizeof(WUDPatchCmd), buf, install_patch_cb); +} + +static void WUDiAppendRuntimePatch(void) { + int i; + + DEBUGPrint("WUDiAppendRuntimePatch()\n"); + + size = 0; + addr = 0; + + for (i = 0; i < (int)sizeof(u32); i++) { + addr <<= 8; + addr += patch_binary[3 - i]; + + size <<= 8; + size += patch_binary[7 - i]; + } + + WUDiRemovePatch(); +} + +void WUDiGetFirmwareVersion(void) { + tBTM_VERSION_INFO version; + BTM_ReadLocalVersion(&version); + + DEBUGPrint("hci_version : %02x\n", version.hci_version); + DEBUGPrint("hci_revision : %04x\n", version.hci_revision); + + DEBUGPrint("lmp_version : %02x\n", version.lmp_version); + DEBUGPrint("lmp_subversion: %04x\n", version.lmp_subversion); + + DEBUGPrint("manufacturer : %04x\n", version.manufacturer); + + DEBUGPrint(" ==> 2045 firmware ver.002.003.014.%d\n", version.hci_revision & 0xFFF); + + if ((version.hci_revision & 0xFFF) == 167) { + WUDiAppendRuntimePatch(); + } else { + WUDiInitSub(); + } +} + +void WUDiInitSub(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + + char devName[] = "Wii"; + DEV_CLASS devClass = { + 0x00, // No designated Major Service Classes + 0x04, // Major Device Class 4 (Audio/Video) + 0x48 // Minor Device Class 18 (Audio/Video -> Gaming/Toy) + }; + + DEBUGPrint("start WUDiInitSub()\n"); + + BTA_DmSetDeviceName(devName); + BTM_SetDeviceClass(devClass); + + BTM_RegisterForVSEvents(&WUDVendorSpecificCallback); + BTM_RegisterForDeviceStatusNotif(&WUDDeviceStatusCallback); + BTM_PmRegister(BTM_PM_REG_SET | BTM_PM_REG_NOTIF, &p->pmID, &WUDPowerManagerCallback); + + BTM_WritePageTimeout(32768); + BTM_SetDefaultLinkPolicy(HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_SNIFF_MODE); + BTM_SetDefaultLinkSuperTout(3200); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (p->stdDevs[i].status == 1) { + WUDiRegisterDevice(p->stdDevs[i].devAddr); + } + } + + enabled = OSDisableInterrupts(); + p->libStatus = WUD_LIB_STATUS_3; + OSRestoreInterrupts(enabled); + + WUDSetVisibility(FALSE, TRUE); +} + +void WUDiEnableStack(void) { + WUDControlBlock* p = &_wcb; + + BTA_HhEnable(BTA_SEC_AUTHENTICATE, WUDHidHostCallback); + + p->stackState = WUD_STATE_STACK_GET_STORED_LINK_KEY; + + OSCreateAlarm(&p->alarm); + OSSetPeriodicAlarm(&p->alarm, __OSGetSystemTime(), OSMillisecondsToTicks(10), EnableStackHandler0); +} + +void WUDiAutoSync(void) { + WUDControlBlock* p = &_wcb; + WUDSyncDeviceCallback pSyncCallback; + s32 result; + BOOL enabled; + + DEBUGPrint("WUDiAutoSync()\n"); + enabled = OSDisableInterrupts(); + + pSyncCallback = p->syncStdCB; + result = WUDIsBusy() ? -1 /* WUD_RESULT_DELETE_BUSY */ + : + WUD_RESULT_DELETE_WAITING; + + OSRestoreInterrupts(enabled); + + if (pSyncCallback != NULL) { + pSyncCallback(result, 0); + } else { + WUDStartSyncDevice(); + } +} + +void WUDiCancelSync() { + DEBUGPrint("WUDiCancelSync()\n"); +} + +void WUDiDeleteAllLinkKeys(void) { + WUDControlBlock* p = &_wcb; + WUDClearDeviceCallback pClearCallback; + s32 result; + BOOL enabled; + + DEBUGPrint("WUDiDeleteAllLinkKeys()\n"); + enabled = OSDisableInterrupts(); + + pClearCallback = p->clearDevCB; + result = WUDIsBusy() ? -1 /* WUD_RESULT_DELETE_BUSY */ + : + WUD_RESULT_DELETE_WAITING; + + OSRestoreInterrupts(enabled); + + if (pClearCallback != NULL) { + pClearCallback(result); + } else { + WUDStartClearDevice(); + } +} + +void WUDiRegisterDevice(BD_ADDR addr) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + tBTA_STATUS status; + BOOL enabled; + + pInfo = WUDiGetDevInfo(addr); + + status = BTA_DmAddDevice(pInfo->devAddr, pInfo->linkKey, 0, FALSE); + DEBUGPrint("BTA_DmAddDevice(): %d\n", status); + + if (WUD_DEV_NAME_IS_CNT(pInfo->conf.devName)) { + tBTA_HH_DEV_DESCR desc; + desc.dl_len = sizeof(descriptor); + desc.dsc_list = descriptor; + + DEBUGPrint("BTA_HhAddDev()\n"); + BTA_HhAddDev(pInfo->devAddr, pInfo->hhAttrMask, pInfo->subclass, pInfo->appID, desc); + } + + enabled = OSDisableInterrupts(); + + if (pInfo->sync_type == 0 || pInfo->sync_type == 4 || pInfo->sync_type == 2 || pInfo->sync_type == 5) { + p->devNums++; + } else { + p->devSmpNums++; + } + + OSRestoreInterrupts(enabled); +} + +void WUDiRemoveDevice(BD_ADDR addr) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + tBTM_STATUS status; + BOOL enabled = OSDisableInterrupts(); + + DEBUGPrint("WUDiRemoveDevice : \n"); + + pInfo = WUDiGetDevInfo(addr); + + if (pInfo != NULL) { + DEBUGPrint(" handle : %d, addr : %02x:%02x:%02x:%02x:%02x:%02x\n", pInfo->devHandle, pInfo->devAddr[0], pInfo->devAddr[1], pInfo->devAddr[2], + pInfo->devAddr[3], pInfo->devAddr[4], pInfo->devAddr[5]); + + DEBUGPrint("remove device info from database.\n"); + + if (WUD_DEV_NAME_IS_CNT(pInfo->conf.devName)) { + DEBUGPrint("BTA_HhRemoveDev()\n"); + DEBUGPrint(" handle : %d\n", pInfo->devHandle); + BTA_HhRemoveDev(pInfo->devHandle); + } + + status = BTA_DmRemoveDevice(pInfo->devAddr); + DEBUGPrint("BTA_DmRemoveDevice(): %d\n", status); + + if (pInfo->sync_type == 0) { + p->devNums--; + } else { + p->devSmpNums--; + } + + memset(pInfo, 0, sizeof *pInfo); + } + + OSRestoreInterrupts(enabled); +} + +WUDDevInfo* WUDiGetDevInfo(BD_ADDR addr) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + BOOL enabled; + int i; + + pInfo = NULL; + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (WUD_BDCMP(p->stdDevs[i].devAddr, addr) == 0) { + pInfo = &p->stdDevs[i]; + break; + } + } + + if (pInfo == NULL) { + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + if (WUD_BDCMP(p->smpDevs[i].devAddr, addr) == 0) { + pInfo = &p->smpDevs[i]; + break; + } + } + } + + OSRestoreInterrupts(enabled); + return pInfo; +} + +WUDDevInfo* WUDiGetDevInfoIndex(int idx) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (0 <= idx && idx < WUD_MAX_DEV_ENTRY_FOR_STD) { + pInfo = &p->stdDevs[idx]; + } else { + pInfo = &p->smpDevs[idx - WUD_MAX_DEV_ENTRY_FOR_STD]; + } + + OSRestoreInterrupts(enabled); + return pInfo; +} + +WUDDevInfo* WUDiGetNewDevInfo(void) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + BOOL enabled; + int i; + + pInfo = NULL; + enabled = OSDisableInterrupts(); + + if (p->syncType == WUD_SYNC_TYPE_STANDARD) { + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (p->stdDevs[i].status == 0) { + DEBUGPrint("new entry index is %d\n", i); + pInfo = &p->stdDevs[i]; + break; + } + } + } else { + pInfo = p->smpListTail->devInfo; + } + + OSRestoreInterrupts(enabled); + return pInfo; +} + +void WUDiRemoveDevInfo(BD_ADDR addr) { + WUDDevInfo* pInfo; + BOOL enabled; + + pInfo = WUDiGetDevInfo(addr); + if (pInfo == NULL) { + return; + } + + enabled = OSDisableInterrupts(); + memset(pInfo, 0, sizeof(WUDDevInfo)); + OSRestoreInterrupts(enabled); +} + +void WUDiClearDevice(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + memset(p->stdDevs, 0, sizeof(WUDDevInfo) * WUD_MAX_DEV_ENTRY_FOR_STD); + memset(p->smpDevs, 0, sizeof(WUDDevInfo) * WUD_MAX_DEV_ENTRY_FOR_SMP); + + p->devNums = 0; + p->devSmpNums = 0; + + p->connectedNum = 0; + p->linkedNum = 0; + p->syncedNum = 0; + + OSRestoreInterrupts(enabled); +} + +u8 WUDiGetDevNumber(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + u8 num = p->devNums; + + OSRestoreInterrupts(enabled); + return num; +} + +u8 WUDiGetDevSmpNumber(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + u8 num = p->devSmpNums; + + OSRestoreInterrupts(enabled); + return num; +} + +u8 WUDiGetConnNumber(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + u8 num = p->connectedNum; + + OSRestoreInterrupts(enabled); + return num; +} + +u8 WUDiGetLinkNum(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); + + u8 num = p->linkedNum; + + OSRestoreInterrupts(enabled); + return num; +} + +void WUDiMoveTopSmpDevInfoPtr(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + if (WUD_BDCMP(p->smpList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + if (WUD_BDCMP(p->smpListHead->devInfo->devAddr, p->smpList[i].devInfo->devAddr) == 0) { + break; + } + + p->smpList[i].prev->next = p->smpList[i].next; + + if (WUD_BDCMP(p->smpListTail->devInfo->devAddr, p->smpList[i].devInfo->devAddr) == 0) { + p->smpListTail = p->smpList[i].prev; + } else { + p->smpList[i].next->prev = p->smpList[i].prev; + } + + p->smpList[i].next = p->smpListHead; + p->smpListHead->prev = &p->smpList[i]; + p->smpListHead = &p->smpList[i]; + + p->smpList[i].prev = NULL; + + break; + } + + OSRestoreInterrupts(enabled); +} + +void WUDiMoveBottomSmpDevInfoPtr(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + if (WUD_BDCMP(p->smpList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + if (WUD_BDCMP(p->smpListTail->devInfo->devAddr, p->smpList[i].devInfo->devAddr) == 0) { + break; + } + + p->smpList[i].next->prev = p->smpList[i].prev; + + if (WUD_BDCMP(p->smpListHead->devInfo->devAddr, p->smpList[i].devInfo->devAddr) == 0) { + p->smpListHead = p->smpList[i].next; + } else { + p->smpList[i].prev->next = p->smpList[i].next; + } + + p->smpList[i].prev = p->smpListTail; + p->smpListTail->next = &p->smpList[i]; + p->smpListTail = &p->smpList[i]; + + p->smpList[i].next = NULL; + + break; + } + + OSRestoreInterrupts(enabled); +} + +WUDDevInfo* WUDiGetRemoveSmpDevice(void) { + return _wcb.smpListTail->devInfo; +} + +void WUDiMoveTopOfDisconnectedSmpDevice(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + int i; + BOOL enabled; + WUDDevInfoList* pIt; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + if (WUD_BDCMP(p->smpList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + for (pIt = p->smpListHead; pIt; pIt = pIt->next) { + if (WUD_BDCMP(pIt->devInfo->devAddr, pInfo->devAddr) == 0) { + continue; + } + + if (pIt->devInfo->status > 1) { + continue; + } + + if (WUD_BDCMP(p->smpListHead->devInfo->devAddr, p->smpList[i].devInfo->devAddr) == 0) { + if (pIt == p->smpListHead->next) { + break; + } + + p->smpListHead = p->smpList[i].next; + } else { + p->smpList[i].prev->next = p->smpList[i].next; + } + + p->smpList[i].next->prev = p->smpList[i].prev; + + if (pIt != p->smpListHead) { + p->smpList[i].prev = pIt->prev; + p->smpList[i].next = pIt; + + pIt->prev->next = &p->smpList[i]; + pIt->prev = &p->smpList[i]; + } else { + p->smpList[i].prev = pIt; + p->smpList[i].next = pIt->next; + + pIt->next->prev = &p->smpList[i]; + pIt->next = &p->smpList[i]; + } + + break; + } + } + + OSRestoreInterrupts(enabled); +} + +#if SDK_AUG2010 +void WUDiMoveTopStdDevInfoPtr(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (WUD_BDCMP(p->stdList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + if (WUD_BDCMP(p->stdListHead->devInfo->devAddr, p->stdList[i].devInfo->devAddr) == 0) { + break; + } + + p->stdList[i].prev->next = p->stdList[i].next; + + if (WUD_BDCMP(p->stdListTail->devInfo->devAddr, p->stdList[i].devInfo->devAddr) == 0) { + p->stdListTail = p->stdList[i].prev; + } else { + p->stdList[i].next->prev = p->stdList[i].prev; + } + + p->stdList[i].next = p->stdListHead; + p->stdListHead->prev = &p->stdList[i]; + p->stdListHead = &p->stdList[i]; + + p->stdList[i].prev = NULL; + + break; + } + + OSRestoreInterrupts(enabled); +} + +void WUDiMoveBottomStdDevInfoPtr(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (WUD_BDCMP(p->stdList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + if (WUD_BDCMP(p->stdListTail->devInfo->devAddr, p->stdList[i].devInfo->devAddr) == 0) { + break; + } + + p->stdList[i].next->prev = p->stdList[i].prev; + + if (WUD_BDCMP(p->stdListHead->devInfo->devAddr, p->stdList[i].devInfo->devAddr) == 0) { + p->stdListHead = p->stdList[i].next; + } else { + p->stdList[i].prev->next = p->stdList[i].next; + } + + p->stdList[i].prev = p->stdListTail; + p->stdListTail->next = &p->stdList[i]; + p->stdListTail = &p->stdList[i]; + + p->stdList[i].next = NULL; + + break; + } + + OSRestoreInterrupts(enabled); +} + +WUDDevInfo* WUDiGetRemoveStdDevice(void) { + return _wcb.stdListTail->devInfo; +} + +void WUDiMoveTopOfDisconnectedStdDevice(WUDDevInfo* pInfo) { + WUDControlBlock* p = &_wcb; + int i; + BOOL enabled; + WUDDevInfoList* pIt; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_STD; i++) { + if (WUD_BDCMP(p->stdList[i].devInfo->devAddr, pInfo->devAddr) != 0) { + continue; + } + + for (pIt = p->stdListHead; pIt; pIt = pIt->next) { + if (WUD_BDCMP(pIt->devInfo->devAddr, pInfo->devAddr) == 0) { + continue; + } + + if (pIt->devInfo->status > 1) { + continue; + } + + if (WUD_BDCMP(p->stdListHead->devInfo->devAddr, p->stdList[i].devInfo->devAddr) == 0) { + if (pIt == p->stdListHead->next) + break; + + p->stdListHead = p->stdList[i].next; + } else { + p->stdList[i].prev->next = p->stdList[i].next; + } + + p->stdList[i].next->prev = p->stdList[i].prev; + + if (pIt != p->stdListHead) { + p->stdList[i].prev = pIt->prev; + p->stdList[i].next = pIt; + + pIt->prev->next = &p->stdList[i]; + pIt->prev = &p->stdList[i]; + } else { + p->stdList[i].prev = pIt; + p->stdList[i].next = pIt->next; + + pIt->next->prev = &p->stdList[i]; + pIt->next = &p->stdList[i]; + } + + break; + } + } + + OSRestoreInterrupts(enabled); +} +#endif + +BOOL WUDIsBusy(void) { + WUDControlBlock* p = &_wcb; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (p->syncState == WUD_STATE_SYNC_START && + p->deleteState == WUD_STATE_DELETE_START && + p->stackState == WUD_STATE_STACK_INITIALIZED && + p->initState == 4) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +static void CleanupCallback(tBTA_STATUS status) { + WUDControlBlock* p = &_wcb; + + if (status == BTA_SUCCESS) { + _initialized = FALSE; + p->libStatus = WUD_LIB_STATUS_0; + return; + } + + DEBUGPrint("WARNING: USB_CLOSE_FAILURE!\n"); +} + +void WUDSecurityCallback(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* pData) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + u8 i; + + tBTA_DM_ENABLE* pEnable; + tBTA_DM_LINK_UP* pLinkUp; + tBTA_DM_LINK_DOWN* pLinkDown; + tBTA_DM_PIN_REQ* pPinReq; + tBTA_DM_AUTH_CMPL* pAuthCmpl; + + DEBUGPrint("WUDSecurityCallback: "); + + switch (event) { + case BTA_DM_ENABLE_EVT: { + pEnable = &pData->enable; + WUD_BDCPY(p->hostAddr, pEnable->bd_addr); + + DEBUGPrint("BTA_ENABLE_EVT\n"); + DEBUGPrint("host : %02x:%02x:%02x:%02x:%02x:%02x\n", p->hostAddr[0], p->hostAddr[1], p->hostAddr[2], p->hostAddr[3], p->hostAddr[4], + p->hostAddr[5]); + + WUDiEnableStack(); + p->libStatus = WUD_LIB_STATUS_2; + break; + } + + case BTA_DM_DISABLE_EVT: { + DEBUGPrint("BTA_DISABLE_EVT\n"); + + BTA_CleanUp(CleanupCallback); + break; + } + + case BTA_DM_PIN_REQ_EVT: { + pPinReq = &pData->pin_req; + + DEBUGPrint("BTA_DM_PIN_REQ_EVT\n"); + + WUDiSetPinCode(pPinReq->bd_addr); + break; + } + + case BTA_DM_AUTH_CMPL_EVT: { + pAuthCmpl = &pData->auth_cmpl; + + DEBUGPrint("BTA_DM_AUTH_CMPL_EVT\n"); + + DEBUGPrint(" addr : %02x:%02x:%02x:%02x:%02x:%02x\n", pAuthCmpl->bd_addr[0], pAuthCmpl->bd_addr[1], pAuthCmpl->bd_addr[2], + pAuthCmpl->bd_addr[3], pAuthCmpl->bd_addr[4], pAuthCmpl->bd_addr[5]); + + // clang-format off + DEBUGPrint(" key : %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + pAuthCmpl->key[0], pAuthCmpl->key[1], pAuthCmpl->key[2], pAuthCmpl->key[3], + pAuthCmpl->key[4], pAuthCmpl->key[5], pAuthCmpl->key[6], pAuthCmpl->key[7], + pAuthCmpl->key[8], pAuthCmpl->key[9], pAuthCmpl->key[10], pAuthCmpl->key[11], + pAuthCmpl->key[12], pAuthCmpl->key[13], pAuthCmpl->key[14], pAuthCmpl->key[15]); + // clang-format on + + DEBUGPrint(" result = %d\n", pAuthCmpl->key_type); + + if (pAuthCmpl->key_type == HCI_LKEY_TYPE_COMBINATION) { + break; + } + + pInfo = WUDiGetDevInfo(pAuthCmpl->bd_addr); + + if (WUD_BDCMP(_work.devAddr, pAuthCmpl->bd_addr) == 0) { + _work.status = 12; + + if (pInfo == NULL) { + pInfo = &_work; + } + } + + memcpy(pInfo->linkKey, pAuthCmpl->key, LINK_KEY_LEN); + break; + } + + case BTA_DM_AUTHORIZE_EVT: { + DEBUGPrint("BTA_DM_AUTHORIZE_EVT\n"); + break; + } + + case BTA_DM_LINK_UP_EVT: { + pLinkUp = &pData->link_up; + + DEBUGPrint("BTA_DM_LINK_UP_EVT\n"); + + DEBUGPrint(" addr : %02x:%02x:%02x:%02x:%02x:%02x\n", pLinkUp->bd_addr[0], pLinkUp->bd_addr[1], pLinkUp->bd_addr[2], pLinkUp->bd_addr[3], + pLinkUp->bd_addr[4], pLinkUp->bd_addr[5]); + + pInfo = WUDiGetDevInfo(pLinkUp->bd_addr); + if (pInfo == NULL && WUD_BDCMP(pLinkUp->bd_addr, _work.devAddr) == 0) { + pInfo = &_work; + } + + if (pInfo == NULL || WUDiGetLinkNum() == WUD_MAX_CHANNELS) { + btm_remove_acl(pLinkUp->bd_addr); + + DEBUGPrint("%s --> %02x:%02x:%02x:%02x:%02x:%02x\n", pInfo == NULL ? "not paired" : "4 links exist", pLinkUp->bd_addr[0], + pLinkUp->bd_addr[1], pLinkUp->bd_addr[2], pLinkUp->bd_addr[3], pLinkUp->bd_addr[4], pLinkUp->bd_addr[5]); + break; + } + + pInfo->status = pInfo->status == 2 ? 12 : 3; + p->linkedNum++; + break; + } + + case BTA_DM_LINK_DOWN_EVT: { + pLinkDown = &pData->link_down; + + DEBUGPrint("BTA_DM_LINK_DOWN_EVT\n"); + + DEBUGPrint(" addr : %02x:%02x:%02x:%02x:%02x:%02x\n", pLinkDown->bd_addr[0], pLinkDown->bd_addr[1], pLinkDown->bd_addr[2], + pLinkDown->bd_addr[3], pLinkDown->bd_addr[4], pLinkDown->bd_addr[5]); + + DEBUGPrint("result: %d\n", pLinkDown->status); + + pInfo = WUDiGetDevInfo(pLinkDown->bd_addr); + if (pInfo != NULL) { + pInfo->status = 1; + p->linkedNum--; + + if (WUD_BDCMP(_work.devAddr, pLinkDown->bd_addr) == 0) { + p->syncState = WUD_STATE_SYNC_ERROR; + } + + if (pLinkDown->status == HCI_ERR_PEER_POWER_OFF) { + for (i = 0; i < WUD_MAX_CHANNELS; i++) { + if (WUD_BDCMP(_scArray.regist[WUD_MAX_DEV_ENTRY_FOR_STD + i].addr, pLinkDown->bd_addr) == 0) { + memset(&_scArray.regist[WUD_MAX_DEV_ENTRY_FOR_STD + i], 0, sizeof(SCBtDeviceInfo)); + + _scFlush = TRUE; + } + } + } + } else if (WUD_BDCMP(_work.devAddr, pLinkDown->bd_addr) == 0) { + p->syncState = WUD_STATE_SYNC_ERROR; + p->linkedNum--; + } else { + DEBUGPrint("this device in not paired\n"); + } + + if (p->linkedNum <= 255 && p->linkedNum >= 250) { + OSReport("WARNING: link num count is reset.\n"); + p->linkedNum = 0; + } + break; + } + + case BTA_DM_SIG_STRENGTH_EVT: { + DEBUGPrint("BTA_DM_SIG_STRENGTH_EVT\n"); + break; + } + + case BTA_DM_BUSY_LEVEL_EVT: { + DEBUGPrint("BTA_DM_BUSY_LEVEL_EVT\n"); + break; + } + } +} + +void WUDSearchCallback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* pData) { + s32 timeout; + + switch (event) { + case BTA_DM_INQ_RES_EVT: { + tBTA_DM_INQ_RES* pResp = &pData->inq_res; + + // clang-format off + DEBUGPrint("INQUIRY RESULT: %02x:%02x:%02x:%02x:%02x:%02x %02x%02x%02x %d\n", + pResp->bd_addr[0], pResp->bd_addr[1], pResp->bd_addr[2], + pResp->bd_addr[3], pResp->bd_addr[4], pResp->bd_addr[5], + pResp->dev_class[0], pResp->dev_class[1], pResp->dev_class[2], + pResp->rssi); + // clang-format on + + _discRssi = pResp->rssi; + + if (_wcb.syncSkipChecks == TRUE || (_wcb.syncSkipChecks == FALSE && WUDiGetLinkNum() < WUD_MAX_CHANNELS - 1)) { + timeout = 4800; + } else { + timeout = 32768; + } + + BTM_WritePageTimeout(timeout); + break; + } + + case BTA_DM_INQ_CMPL_EVT: { + DEBUGPrint("INQUIRY_COMPLETED\n"); + break; + } + + case BTA_DM_DISC_RES_EVT: { + tBTA_DM_DISC_RES* dmDiscRes = &pData->disc_res; + + WUD_BDCPY(_discResp.devAddr, dmDiscRes->bd_addr); + memcpy(_discResp.devName, dmDiscRes->bd_name, sizeof(_discResp.devName)); + + _discResp.services = dmDiscRes->services; + _discNumResps++; + + // clang-format off + DEBUGPrint("DISCOVER RESULT: %02x:%02x:%02x:%02x:%02x:%02x %s (%04x)\n", + _discResp.devAddr[0], _discResp.devAddr[1], _discResp.devAddr[2], + _discResp.devAddr[3], _discResp.devAddr[4], _discResp.devAddr[5], + _discResp.devName, _discResp.services); + // clang-format on + break; + } + + case BTA_DM_DISC_CMPL_EVT: { + DEBUGPrint("DISCOVER COMPLETED\n"); + + _wcb.syncState = WUD_STATE_SYNC_CHECK_SEARCH_RESULT; + break; + } + + case BTA_DM_SEARCH_CANCEL_CMPL_EVT: { + DEBUGPrint("SEARCH CANCEL\n\n"); + + _discNumResps = 0; + memset(&_discResp, 0, sizeof(WUDDiscResp)); + + _wcb.syncState = WUD_STATE_SYNC_CHECK_SEARCH_RESULT; + break; + } + + default: { + DEBUGPrint("Warning: Search Callback returns invalid event\n"); + break; + } + } +} + +void WUDVendorSpecificCallback(UINT8 len, UINT8* pData) { +#pragma unused(len) + + u8 event = pData[0]; + WUDControlBlock* p = &_wcb; + + switch (event) { + case WUD_VSE_INITIATE_PAIRING: { + DEBUGPrint("VSE:- INITIATE_PAIRING\n"); + WUDiAutoSync(); + break; + } + + case WUD_VSE_DELETE_ALL_KEYS: { + DEBUGPrint("VSE:- DELETE_ALL_KEYS\n"); + WUDiDeleteAllLinkKeys(); + break; + } + + case WUD_VSE_SI_PORT_STATUS: { + DEBUGPrint("VSE:- SI_PORT_STATUS status = %d\n", pData[1]); + p->serialPortStatus = pData[1]; + break; + } + + case WUD_VSE_WATCH_DOG_RESET_HW: { + DEBUGPrint("VSE:- WATCH_DOG_RESET HW error = %d\n", pData[1]); + + // clang-format off + OSPanic(__FILE__, 3484, "MODULE FATAL ERROR\n"); + // clang-format on + break; + } + } +} + +void WUDDeviceStatusCallback(tBTM_DEV_STATUS status) { + DEBUGPrint("WUDDeviceStatusCallback\n"); + + if (status == BTM_DEV_STATUS_CMD_TOUT) { + OSReport("---- WARNING: USB FATAL ERROR! ----\n"); + } +} + +void WUDStoredLinkKeyCallback(void* p1) { + tBTM_BD_ADDR_LINK_KEY_PAIR* pPair; + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + int i; + + tBTM_STORED_LINK_KEYS_EVT* pData = p1; + tBTM_READ_STORED_LINK_KEY_COMPLETE* pRead; + tBTM_WRITE_STORED_LINK_KEY_COMPLETE* pWrite; + tBTM_DELETE_STORED_LINK_KEY_COMPLETE* pDelete; + tBTM_RETURN_LINK_KEYS_EVT* pReturn; + + switch (pData->event) { + case BTM_CB_EVT_RETURN_LINK_KEYS: { + pReturn = p1; + + DEBUGPrint("BTM_CB_EVT_RETURN_LINK_KEYS\n"); + + pPair = (tBTM_BD_ADDR_LINK_KEY_PAIR*)(pReturn + 1); + i = 0; + + while (i < pReturn->num_keys) { + pInfo = WUDiGetDevInfo(pPair->bd_addr); + + DEBUGPrint("BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", pPair->bd_addr[0], pPair->bd_addr[1], pPair->bd_addr[2], pPair->bd_addr[3], + pPair->bd_addr[4], pPair->bd_addr[5]); + + // clang-format off + DEBUGPrint("LINKKEY: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + pPair->link_key[0], pPair->link_key[1], pPair->link_key[2], pPair->link_key[3], + pPair->link_key[4], pPair->link_key[5], pPair->link_key[6], pPair->link_key[7], + pPair->link_key[8], pPair->link_key[9], pPair->link_key[10], pPair->link_key[11], + pPair->link_key[12], pPair->link_key[13], pPair->link_key[14], pPair->link_key[15]); + // clang-format on + + if (pInfo == NULL) { + DEBUGPrint("this device is not stored in NAND\n"); + + pInfo = WUDiGetNewDevInfo(); + + if (pInfo == NULL) { + for (i = 0; i < WUD_MAX_DEV_ENTRY_FOR_SMP; i++) { + if (p->smpDevs[i].status == 0) { + pInfo = &p->smpDevs[i]; + break; + } + } + } + + if (pInfo) { + pInfo->UNK_0x5C = 1; + pInfo->status = 1; + + WUD_BDCPY(pInfo->devAddr, pPair->bd_addr); + memcpy(pInfo->linkKey, pPair->link_key, LINK_KEY_LEN); + } + } else { + WUD_BDCPY(pInfo->devAddr, pPair->bd_addr); + memcpy(pInfo->linkKey, pPair->link_key, LINK_KEY_LEN); + + if (pInfo->UNK_0x5C == 2) { + pInfo->UNK_0x5C = 3; + } + + WUD_BDCPY(p->pairAddr, pPair->bd_addr); + DEBUGPrint(" LAST: %02x:%02x:%02x:%02x:%02x:%02x\n", p->pairAddr[0], p->pairAddr[1], p->pairAddr[2], p->pairAddr[3], p->pairAddr[4], + p->pairAddr[5]); + } + + pPair++; + i++; + } + + break; + } + + case BTM_CB_EVT_READ_STORED_LINK_KEYS: { + pRead = p1; + + DEBUGPrint("BTM_CB_EVT_READ_STORED_LINK_KEYS\n"); + DEBUGPrint(" status: %d max_keys: %d num_keys: %d\n", pRead->status, pRead->max_keys, pRead->read_keys); + + p->linkKeyState = WUD_STATE_LINK_KEY_START; + break; + } + + case BTM_CB_EVT_WRITE_STORED_LINK_KEYS: { + pWrite = p1; + + DEBUGPrint("BTM_CB_EVT_WRITE_STORED_LINK_KEYS\n"); + DEBUGPrint(" status: %d num_keys: %d\n", pWrite->status, pWrite->num_keys); + + p->linkKeyState = WUD_STATE_LINK_KEY_START; + break; + } + + case BTM_CB_EVT_DELETE_STORED_LINK_KEYS: { + pDelete = p1; + + DEBUGPrint("BTM_CB_EVT_DELETE_STORED_LINK_KEYS\n"); + DEBUGPrint(" status: %d num_keys: %d\n", pDelete->status, pDelete->num_keys); + + if (pDelete->num_keys == 0) { + DEBUGPrint("WARNING: no entry is deleted\n"); + } + + p->linkKeyState = WUD_STATE_LINK_KEY_START; + break; + } + + default: { + // clang-format off + OSPanic(__FILE__, 3636, "Unknown event\n"); + // clang-format on + } + } +} + +void WUDPowerManagerCallback(BD_ADDR addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hciStatus) { +#pragma unused(value) + + WUDDevInfo* pInfo; + + DEBUGPrint("WUDPowerManagerCallback\n"); + DEBUGPrint("hci_status = %d", hciStatus); + + pInfo = WUDiGetDevInfo(addr); + if (pInfo == NULL) { + if (WUD_BDCMP(_work.devAddr, addr) == 0) { + pInfo = &_work; + } + } + + switch (status) { + case BTM_PM_STS_ACTIVE: { + pInfo->status = 8; + break; + } + + case BTM_PM_STS_SNIFF: { + pInfo->status = 9; + break; + } + } + + DEBUGPrint(" addr = %02x:%02x:%02x:%02x:%02x:%02x, status = %d\n", pInfo->devAddr[0], pInfo->devAddr[1], pInfo->devAddr[2], pInfo->devAddr[3], + pInfo->devAddr[4], pInfo->devAddr[5], pInfo->status); +} + +BD_ADDR_PTR _WUDGetDevAddr(UINT8 handle) { + BD_ADDR_PTR pAddr; + BOOL enabled = OSDisableInterrupts(); + + if (handle < WUD_MAX_DEV_ENTRY) { + pAddr = _dev_handle_to_bda[handle]; + + } else { + pAddr = NULL; + } + + OSRestoreInterrupts(enabled); + return pAddr; } u16 _WUDGetQueuedSize(s8 dev_handle) { u16 queuedSize; BOOL intrStatus = OSDisableInterrupts(); - if (dev_handle >= 0 && dev_handle < WUD_MAX_DEV_ENTRY) + if (dev_handle >= 0 && dev_handle < WUD_MAX_DEV_ENTRY) { queuedSize = WUDiGetQueueSizeForHandle(dev_handle); - else + } else { queuedSize = 0; + } OSRestoreInterrupts(intrStatus); return queuedSize; @@ -38,36 +2848,53 @@ u16 _WUDGetNotAckedSize(s8 dev_handle) { u16 notAckedSize; BOOL intrStatus = OSDisableInterrupts(); - if (dev_handle >= 0 && dev_handle < WUD_MAX_DEV_ENTRY) + if (dev_handle >= 0 && dev_handle < WUD_MAX_DEV_ENTRY) { notAckedSize = WUDiGetNotAckNumForHandle(dev_handle); - else + } else { notAckedSize = 0; + } OSRestoreInterrupts(intrStatus); return notAckedSize; } u8 _WUDGetLinkNumber(void) { - wud_cb_st* p_wcb = &__rvl_wudcb; - BOOL intrStatus = OSDisableInterrupts(); - u8 linkedNum = p_wcb->linkedNum; + WUDControlBlock* p = &_wcb; + BOOL enabled = OSDisableInterrupts(); - OSRestoreInterrupts(intrStatus); - return linkedNum; + u8 num = p->linkedNum; + + OSRestoreInterrupts(enabled); + return num; } -u16 WUDiGetQueueSizeForHandle(u8 dev_handle) { +// not sure if this is a fakematch or an actual version difference of some kind +#if SDK_AUG2010 +inline u16 WUDiGetQueueSizeForHandle(u8 dev_handle) { +#else +inline u16 WUDiGetQueueSizeForHandle(u32 dev_handle) { +#endif return _dev_handle_queue_size[dev_handle]; } -u16 WUDiGetNotAckNumForHandle(u8 dev_handle) { +// see comment for WUDiGetQueueSizeForHandle +#if SDK_AUG2010 +inline u16 WUDiGetNotAckNumForHandle(u8 dev_handle) { +#else +inline u16 WUDiGetNotAckNumForHandle(u32 dev_handle) { +#endif return _dev_handle_notack_num[dev_handle]; } -BOOL WUDStartSyncSimple(void) { - // NONMATCHING +void _WUDEnableTestMode() { + DEBUGPrint("_WUDEnableTestMode\n"); } -BOOL WUDStartFastSyncSimple(void) { - // NONMATCHING +void _WUDStartSyncDevice() { + DEBUGPrint("_WUDStartSyncDevice()\n"); +} + +void _WUDDeleteStoreDevice() { + DEBUGPrint("_WUDDeleteStoreDevice()\n"); + DEBUGPrint("dev number = %d\n", 0); } diff --git a/src/revolution/wud/WUDHidHost.c b/src/revolution/wud/WUDHidHost.c new file mode 100644 index 0000000000..aaae4d0aa2 --- /dev/null +++ b/src/revolution/wud/WUDHidHost.c @@ -0,0 +1,261 @@ +#include <revolution/wud.h> +#include <revolution/wud/__wud.h> +#include <revolution/wpad/bte.h> +#include <revolution/os/OSInterrupt.h> +#include <cstring> + +#define DEBUGPrint WUD_DEBUGPrint + +// TODO(kiwi) Is this from BTA? +#define WUD_HH_CUSTOM_EVT 15 + +typedef struct WUD_HH_EVT15 { + /* 0x00 */ u16 status0; + /* 0x02 */ u16 status1; + /* 0x04 */ u16 linkedNum; + + /* 0x06 */ struct { + /* 0x00 */ UINT8 handle; + /* 0x02 */ UINT16 queueSize; + /* 0x04 */ UINT16 notAckNum; + } devices[]; +} WUD_HH_EVT15; + +void WUDHidHostCallback(tBTA_HH_EVT event, tBTA_HH* pData) { + WUDControlBlock* p = &_wcb; + WUDDevInfo* pInfo; + tBTA_HH_CONN* pConn; + tBTA_HH_CBDATA* pCbData; + WUD_HH_EVT15* pEvt15; + int i; + + switch (event) { + case BTA_HH_ENABLE_EVT: { + DEBUGPrint("BTA_HH_ENABLE_EVT\n"); + + p->hhFlags |= 1; + break; + } + + case BTA_HH_DISABLE_EVT: { + DEBUGPrint("BTA_HH_DISABLE_EVT\n"); + break; + } + + case BTA_HH_OPEN_EVT: { + pConn = &pData->conn; + + DEBUGPrint("BTA_HH_OPEN_EVT\n"); + + DEBUGPrint("handle: %d, addr: %02x:%02x:%02x:%02x:%02x:%02x\n", pConn->handle, pConn->bda[0], pConn->bda[1], pConn->bda[2], pConn->bda[3], + pConn->bda[4], pConn->bda[5]); + + if (pConn->status == BTA_HH_OK) { + pInfo = &_work; + + if (WUD_BDCMP(pInfo->devAddr, pConn->bda) != 0) { + pInfo = WUDiGetDevInfo(pConn->bda); + } + + switch (pInfo->status) { + case 12: { + p->syncState = WUD_STATE_SYNC_REGISTER_DEVICE; + break; + } + + case 2: { + p->syncState = WUD_STATE_SYNC_COMPLETE; + break; + } + } + + pInfo->status = 8; + pInfo->devHandle = pConn->handle; + p->connectedNum++; + + pInfo = WUDiGetDevInfo(pConn->bda); + if (pInfo == NULL) { + pInfo = &_work; + } + + _dev_handle_to_bda[pConn->handle] = pInfo->devAddr; + _dev_handle_queue_size[pConn->handle] = 0; + _dev_handle_notack_num[pConn->handle] = 0; + + if (pInfo->sync_type == 3 || pInfo->sync_type == 1) { + WUDiMoveTopSmpDevInfoPtr(pInfo); + } + + WUDSetSniffMode(pInfo->devAddr, 8); + + if (p->hidConnCB != NULL) { + p->hidConnCB(pConn->handle, TRUE); + } + } else { + DEBUGPrint("error code: %d\n", pConn->status); + + if (!memcmp(pConn->bda, _work.devAddr, 6)) { + if (p->syncState != 0) { + if (_work.status == 2) { + if (WUDiGetDevInfo(pConn->bda) && pConn->status == 12) { + WUDiRemoveDevice(pConn->bda); + p->linkedNum--; + } + + p->syncState = 255; + } + } + } + } + } + + break; + case BTA_HH_CLOSE_EVT: { + pCbData = &pData->dev_status; + + DEBUGPrint("BTA_HH_CLOSE_EVT\n"); + + p->connectedNum--; + + DEBUGPrint("device handle : %d status = %d\n", pCbData->handle, pCbData->status); + + _dev_handle_to_bda[pCbData->handle] = NULL; + _dev_handle_queue_size[pCbData->handle] = 0; + _dev_handle_notack_num[pCbData->handle] = 0; + + if (p->hidConnCB != NULL) { + p->hidConnCB(pCbData->handle, FALSE); + } + break; + } + + case BTA_HH_SET_RPT_EVT: { + DEBUGPrint("BTA_HH_SET_RPT_EVT\n"); + break; + } + case BTA_HH_GET_RPT_EVT: { + DEBUGPrint("BTA_HH_GET_RPT_EVT\n"); + break; + } + + case BTA_HH_SET_PROTO_EVT: { + DEBUGPrint("BTA_HH_SET_PROTO_EVT\n"); + break; + } + case BTA_HH_GET_PROTO_EVT: { + DEBUGPrint("BTA_HH_GET_PROTO_EVT\n"); + break; + } + + case BTA_HH_SET_IDLE_EVT: { + DEBUGPrint("BTA_HH_SET_IDLE_EVT\n"); + break; + } + case BTA_HH_GET_IDLE_EVT: { + DEBUGPrint("BTA_HH_GET_IDLE_EVT\n"); + break; + } + + case BTA_HH_GET_DSCP_EVT: { + DEBUGPrint("BTA_HH_GET_DCSP_EVT\n"); + break; + } + + case BTA_HH_ADD_DEV_EVT: { + pConn = &pData->dev_info; + + DEBUGPrint("BTA_HH_ADD_DEV_EVT\n"); + + // clang-format off + DEBUGPrint("result: %d, handle: %d, addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + pConn->status, pConn->handle, + pConn->bda[0], pConn->bda[1], pConn->bda[2], + pConn->bda[3], pConn->bda[4], pConn->bda[5]); + // clang-format on + + pInfo = WUDiGetDevInfo(pConn->bda); + pInfo->devHandle = pConn->handle; + break; + } + + case BTA_HH_RMV_DEV_EVT: { + pConn = &pData->dev_info; + + DEBUGPrint("BTA_HH_RMV_DEV_EVT\n"); + + // clang-format off + DEBUGPrint("result: %d, handle: %d, addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + pConn->status, pConn->handle, + pConn->bda[0], pConn->bda[1], pConn->bda[2], + pConn->bda[3], pConn->bda[4], pConn->bda[5]); + // clang-format on + break; + } + + case BTA_HH_VC_UNPLUG_EVT: { + DEBUGPrint("BTA_HH_VS_UNPLUG_EVT\n"); + break; + } + + case WUD_HH_CUSTOM_EVT: { + pEvt15 = (WUD_HH_EVT15*)pData; + + p->bufferStatus0 = pEvt15->status0; + p->bufferStatus1 = pEvt15->status1; + + if (p->linkedNum < pEvt15->linkedNum) { + OSReport("WARNING: link num count is modified.\n"); + p->linkedNum = pEvt15->linkedNum; + } + + for (i = 0; i < pEvt15->linkedNum; i++) { + if (pEvt15->devices[i].handle < WUD_MAX_DEV_ENTRY) { + _dev_handle_queue_size[pEvt15->devices[i].handle] = pEvt15->devices[i].queueSize; + + _dev_handle_notack_num[pEvt15->devices[i].handle] = pEvt15->devices[i].notAckNum; + } + } + + break; + } + } +} + +void bta_hh_co_data(UINT8 handle, UINT8* pReport, UINT16 len, tBTA_HH_PROTO_MODE mode, UINT8 subClass, UINT8 appId) { +#pragma unused(mode) +#pragma unused(subClass) + + WUDControlBlock* p = &_wcb; + + if (appId == 3) { + if (p->hidRecvCB != NULL) { + p->hidRecvCB(handle, pReport, len); + } + } else { + DEBUGPrint("Invalid app_id [%d]\n", appId); + } +} + +void bta_hh_co_open(UINT8 handle, UINT8 subClass, UINT16 attrMask, UINT8 appId) { +#pragma unused(handle) +#pragma unused(subClass) +#pragma unused(attrMask) +#pragma unused(appId) + + DEBUGPrint("bta_hh_co_open()\n"); +} + +void bta_hh_co_close(UINT8 handle, UINT8 appId) { +#pragma unused(handle) +#pragma unused(appId) + + DEBUGPrint("bta_hh_co_close()\n"); +} + +BOOL bta_dm_co_get_compress_memory(tBTA_SYS_ID id, UINT8** ppMemory, UINT32* memorySize) { +#pragma unused(id) +#pragma unused(ppMemory) +#pragma unused(memorySize) + + return FALSE; +} diff --git a/src/revolution/wud/__wud.h b/src/revolution/wud/__wud.h index dace1a2f71..9a7149dbca 100644 --- a/src/revolution/wud/__wud.h +++ b/src/revolution/wud/__wud.h @@ -2,77 +2,237 @@ #define _REVOLUTION_WUD_PRIVATE_H_ #include <revolution/os.h> +#include <revolution/sc.h> #include <revolution/wpad/bte.h> +#include <revolution/wud.h> #ifdef __cplusplus extern "C" { #endif -#define WUD_MAX_DEV_ENTRY_FOR_STD 10 -#define WUD_MAX_DEV_ENTRY_FOR_SMP 6 +#define WUD_BDCMP(LHS, RHS) memcmp(LHS, RHS, BD_ADDR_LEN) +#define WUD_BDCPY(DST, SRC) memcpy(DST, SRC, BD_ADDR_LEN) -#define WUD_MAX_DEV_ENTRY 16 +// clang-format off +#define WUD_DEV_NAME_IS(NAME, VALUE) \ + (memcmp(NAME, VALUE, sizeof(VALUE) - 1) == 0) -#define WUD_DEV_HANDLE_INVALID (-1) +#define WUD_DEV_NAME_IS_CNT(NAME) \ + WUD_DEV_NAME_IS(NAME, "Nintendo RVL-CNT") -struct WUDDevInfoList { +#define WUD_DEV_NAME_IS_CNT_01(NAME) \ + WUD_DEV_NAME_IS(NAME, "Nintendo RVL-CNT-01") +// clang-format on + +typedef enum { + WUD_STATE_SYNC_START = 0, + WUD_STATE_SYNC_PREPARE_SEARCH = 1, + WUD_STATE_SYNC_START_SEARCH = 2, + WUD_STATE_SYNC_WAIT_FOR_SEARCH_RESULT = 3, + WUD_STATE_SYNC_CHECK_SEARCH_RESULT = 4, + WUD_STATE_SYNC_IS_EXISTED_DEVICE = 5, + WUD_STATE_SYNC_6 = 6, + WUD_STATE_SYNC_STORED_LINK_KEY_TO_EEPROM = 7, + WUD_STATE_SYNC_WAIT_FOR_STORING = 8, + WUD_STATE_SYNC_WAIT_FOR_READING = 10, + WUD_STATE_SYNC_11 = 11, + WUD_STATE_SYNC_12 = 12, + WUD_STATE_SYNC_13 = 13, + WUD_STATE_SYNC_DONE = 14, + WUD_STATE_SYNC_TRY_CONNECT = 15, + WUD_STATE_SYNC_PREPARE_FOR_EXISTED_DEVICE = 16, + WUD_STATE_SYNC_PREPARE_FOR_UNKNOWN_DEVICE = 17, + WUD_STATE_SYNC_REGISTER_DEVICE = 18, + WUD_STATE_SYNC_VIRGIN_SIMPLE = 19, + WUD_STATE_SYNC_VIRGIN_STANDARD = 20, + WUD_STATE_SYNC_CHANGE_SIMPLE_TO_STANDARD = 21, + WUD_STATE_SYNC_STORED_DEV_INFO_TO_NAND = 22, + WUD_STATE_SYNC_COMPLETE = 23, + WUD_STATE_SYNC_WAIT_FOR_INCOMING = 24, + WUD_STATE_SYNC_SC_FLUSH = 25, + WUD_STATE_SYNC_CANCEL_SEARCH = 26, + WUD_STATE_SYNC_WAIT_FOR_START_SEARCH = 29, + WUD_STATE_SYNC_ERROR = 255, +} WUDSyncState; + +typedef enum { + WUD_STATE_DELETE_START = 0, + WUD_STATE_DELETE_DISALLOW_INCOMING = 1, + WUD_STATE_DELETE_DISCONNECT_ALL = 2, + WUD_STATE_DELETE_CLEANUP_DATABASE = 3, + WUD_STATE_DELETE_CLEANUP_SETTING = 5, + WUD_STATE_DELETE_6 = 6, + WUD_STATE_DELETE_7 = 7, + WUD_STATE_DELETE_DONE = 8 +} WUDDeleteState; + +typedef enum { + WUD_RESULT_DELETE_BUSY = -1, + WUD_RESULT_DELETE_WAITING, + WUD_RESULT_DELETE_COMPLETE, +} WUDDeleteResult; + +typedef enum { + WUD_STATE_LINK_KEY_START = 0, + WUD_STATE_LINK_KEY_READING = 1, + WUD_STATE_LINK_KEY_WRITING = 2, + WUD_STATE_LINK_KEY_DELETING = 3, + WUD_STATE_LINK_KEY_ERROR = 255, +} WUDLinkKeyState; + +typedef enum { + WUD_STATE_STACK_START = 0, + WUD_STATE_STACK_GET_STORED_LINK_KEY = 1, + WUD_STATE_STACK_CHECK_DEVICE_INFO = 2, + WUD_STATE_STACK_DONE = 3, + WUD_STATE_STACK_INITIALIZED = 4, + WUD_STATE_STACK_ERROR = 255, +} WUDStackState; + +typedef enum { + WUD_STATE_INIT_START = 0, + WUD_STATE_INIT_WAIT_FOR_INITIALIZATION = 1, + WUD_STATE_INIT_GET_DEV_INFO = 2, + WUD_STATE_INIT_DONE = 3, + WUD_STATE_INIT_INITIALIZED = 4, + WUD_STATE_INIT_ERROR = 255, +} WUDInitState; + +typedef enum { + WUD_STATE_SHUTDOWN_START = 0, + WUD_STATE_SHUTDOWN_STORE_SETTINGS = 1, + WUD_STATE_SHUTDOWN_FLUSH_SETTINGS = 2, + WUD_STATE_SHUTDOWN_DONE = 3, + WUD_STATE_SHUTDOWN_ERROR = 255, +} WUDShutdownState; + +typedef enum { + WUD_VSE_INITIATE_PAIRING = 8, + WUD_VSE_DELETE_ALL_KEYS, + WUD_VSE_SI_PORT_STATUS, + WUD_VSE_WATCH_DOG_RESET_HW = 16, +} WUDVendorSpecificEvent; + +typedef struct WUDDevInfoList { /* 0x00 */ WUDDevInfo* devInfo; /* 0x04 */ struct WUDDevInfoList* prev; /* 0x08 */ struct WUDDevInfoList* next; -}; // size 0x0c - -typedef struct /* possibly untagged, like kpad */ { - /* 0x000 */ WUDSyncDeviceCallback* syncStdCB; - /* 0x004 */ WUDSyncDeviceCallback* syncSmpCB; - /* 0x008 */ WUDClearDeviceCallback* clearDevCB; - /* 0x00c */ u8 syncState; - /* 0x00d */ u8 deleteState; - /* 0x00e */ u8 linkKeyState; - /* 0x00f */ u8 stackState; +} WUDDevInfoList; + +typedef struct WUDDiscResp { + /* 0x000 */ BD_ADDR devAddr; + /* 0x006 */ char devName[64]; + /* 0x046 */ u8 unk_0x46[0x100 - 0x46]; + /* 0x100 */ tBTA_SERVICE_MASK services; + /* 0x104 */ u8 unk_0x104[0x104 - 0x100]; +} WUDDiscResp; + +typedef struct WUDPatchCmd { + /* 0x00 */ u8 data[13]; +} WUDPatchCmd; + +typedef struct WUDPatchList { + /* 0x00 */ u8 num; + /* 0x01 */ WUDPatchCmd cmds[]; +} WUDPatchList; + +#define WUD_PATCH_BUFFER_SIZE 0xFF +#define WUD_MAX_PATCHES (WUD_PATCH_BUFFER_SIZE / (s32)sizeof(WUDPatchCmd)) + +typedef struct WUDCB { + /* 0x000 */ WUDSyncDeviceCallback syncStdCB; + /* 0x004 */ WUDSyncDeviceCallback syncSmpCB; + /* 0x008 */ WUDClearDeviceCallback clearDevCB; + + /* 0x00C */ u8 syncState; + /* 0x00D */ u8 deleteState; + /* 0x00E */ u8 linkKeyState; + /* 0x00F */ u8 stackState; /* 0x010 */ u8 initState; /* 0x011 */ u8 shutdownState; + /* 0x012 */ u8 devNums; /* 0x013 */ u8 devSmpNums; - /* 0x014 */ struct WUDDevInfoList* smpListHead; - /* 0x018 */ struct WUDDevInfoList* smpListTail; - /* 0x01c */ struct WUDDevInfoList smpList[WUD_MAX_DEV_ENTRY_FOR_SMP]; - /* 0x064 */ struct WUDDevInfoList* stdListHead; - /* 0x068 */ struct WUDDevInfoList* stdListTail; - /* 0x06c */ struct WUDDevInfoList stdList[WUD_MAX_DEV_ENTRY_FOR_STD]; - /* 0x0e4 */ WUDDevInfo stdDevs[WUD_MAX_DEV_ENTRY_FOR_STD]; - /* 0x4a4 */ WUDDevInfo smpDevs[WUD_MAX_DEV_ENTRY_FOR_SMP]; - /* 0x6e4 */ u8 connectedNum; - /* 0x6e5 */ u8 linkedNum; - /* 0x6e6 */ u8 syncedNum; - /* 0x6e7 */ u8 syncSkipChecks; - /* 0x6e8 */ s8 syncLoopNum; - /* 0x6e9 */ u8 syncType; - /* 0x6ea */ u8 connectable; - /* 0x6eb */ u8 discoverable; - /* 0x6ec */ WUDHidReceiveCallback* hidRecvCB; - /* 0x6f0 */ WUDHidConnectCallback* hidConnCB; - /* 0x6f4 */ WUDAllocFunc* allocFunc; - /* 0x6f8 */ WUDFreeFunc* freeFunc; - /* 0x6fc */ BD_ADDR pairAddr; - /* 0x702 */ BD_ADDR hostAddr; - /* 0x708 */ s8 libStatus; - /* 0x709 */ u8 siPortStatus; - /* 0x70a */ u8 pmID; - /* 0x70b */ s8 syncRssi; - /* 0x710 */ OSAlarm alarm; - /* 0x740 */ u32 hhFlags; // some flags maybe? - /* 0x744 */ u16 bufferStatus0; - /* 0x746 */ u16 bufferStatus1; - /* 0x748 */ s8 initWaitDeviceUpFrames; - /* 0x749 */ s8 waitStartSearchFrames; - /* 0x74a */ s16 waitIncomingFrames; -} wud_cb_st; // size 0x750 + /* 0x014 */ WUDDevInfoList* smpListHead; + /* 0x018 */ WUDDevInfoList* smpListTail; + /* 0x01C */ WUDDevInfoList smpList[WUD_MAX_DEV_ENTRY_FOR_SMP]; + +#if SDK_AUG2010 + /* 0x064 */ WUDDevInfoList* stdListHead; + /* 0x068 */ WUDDevInfoList* stdListTail; + /* 0x06C */ WUDDevInfoList stdList[WUD_MAX_DEV_ENTRY_FOR_STD]; +#endif + + /* 0x064 */ WUDDevInfo stdDevs[WUD_MAX_DEV_ENTRY_FOR_STD]; + /* 0x424 */ WUDDevInfo smpDevs[WUD_MAX_DEV_ENTRY_FOR_SMP]; + + /* 0x664 */ u8 connectedNum; + /* 0x665 */ u8 linkedNum; + /* 0x666 */ u8 syncedNum; + + /* 0x667 */ u8 syncSkipChecks; + /* 0x668 */ s8 syncLoopNum; + /* 0x669 */ u8 syncType; + + /* 0x66A */ u8 connectable; + /* 0x66B */ u8 discoverable; + + /* 0x66C */ WUDHidRecvCallback hidRecvCB; + /* 0x670 */ WUDHidConnCallback hidConnCB; + + /* 0x674 */ WUDAllocFunc allocFunc; + /* 0x678 */ WUDFreeFunc freeFunc; + + /* 0x67C */ BD_ADDR pairAddr; + /* 0x682 */ BD_ADDR hostAddr; + + /* 0x688 */ s8 libStatus; + + /* 0x689 */ u8 serialPortStatus; + /* 0x68A */ UINT8 pmID; + /* 0x68B */ s8 syncRssi; + /* 0x670 */ OSAlarm alarm; + /* 0x6C0 */ u32 hhFlags; + + /* 0x6C4 */ u16 bufferStatus0; + /* 0x6C6 */ u16 bufferStatus1; +#if SDK_AUG2010 + /* 0x748 */ u8 unk_0x748[0x750 - 0x748]; +#endif +} WUDControlBlock; + +#if SDK_AUG2010 +extern WUDControlBlock __rvl_wudcb; +#define _wcb __rvl_wudcb +#else +extern WUDControlBlock _wcb; +#endif +extern WUDDevInfo _work; + +extern SCBtDeviceInfoArray _scArray; + +extern BD_ADDR_PTR _dev_handle_to_bda[WUD_MAX_DEV_ENTRY]; +extern u16 _dev_handle_queue_size[WUD_MAX_DEV_ENTRY]; +extern u16 _dev_handle_notack_num[WUD_MAX_DEV_ENTRY]; + +#if SDK_AUG2010 u16 WUDiGetQueueSizeForHandle(u8 dev_handle); u16 WUDiGetNotAckNumForHandle(u8 dev_handle); +#else +u16 WUDiGetQueueSizeForHandle(u32 dev_handle); +u16 WUDiGetNotAckNumForHandle(u32 dev_handle); +#endif + +/* wud/WUDHidHost.c */ +void WUDHidHostCallback(tBTA_HH_EVT event, tBTA_HH *p_data); + +/* wud/debug_msg.c */ + +void WUD_DEBUGPrint(const char* fmt, ...); #ifdef __cplusplus } #endif -#endif // _REVOLUTION_WUD_PRIVATE_H_ +#endif /* _REVOLUTION_WUD_PRIVATE_H_ */ diff --git a/src/revolution/wud/debug_msg.c b/src/revolution/wud/debug_msg.c index 43ab011cb5..8e05cc0499 100644 --- a/src/revolution/wud/debug_msg.c +++ b/src/revolution/wud/debug_msg.c @@ -1,6 +1,8 @@ -#include <revolution/wud/debug_msg.h> +#include <revolution/wud.h> + +#include <va_list> void WUD_DEBUGPrint(const char* msg, ...) { - // NONMATCHING + va_list list; } |
