From 3e39f97fe5d1773b3f72a549bb550b7418b75701 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Thu, 6 Jun 2019 20:52:33 -0400 Subject: [PATCH] Added support for hiddbg Hdls. --- nx/include/switch.h | 1 + nx/include/switch/services/hiddbg.h | 68 +++++ nx/source/services/hiddbg.c | 374 ++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 nx/include/switch/services/hiddbg.h create mode 100644 nx/source/services/hiddbg.c diff --git a/nx/include/switch.h b/nx/include/switch.h index d7b52ba3..467736f8 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -68,6 +68,7 @@ extern "C" { #include "switch/services/usbds.h" #include "switch/services/usbhs.h" #include "switch/services/hid.h" +#include "switch/services/hiddbg.h" #include "switch/services/hidsys.h" #include "switch/services/irs.h" #include "switch/services/pl.h" diff --git a/nx/include/switch/services/hiddbg.h b/nx/include/switch/services/hiddbg.h new file mode 100644 index 00000000..f914de4b --- /dev/null +++ b/nx/include/switch/services/hiddbg.h @@ -0,0 +1,68 @@ +/** + * @file hiddbg.h + * @brief hid:dbg service IPC wrapper. + * @author yellows8 + */ +#pragma once +#include "../types.h" +#include "../services/hid.h" +#include "../services/sm.h" + +/// HdlsNpadAssignment +typedef struct { + u8 unk_x0[0x208]; ///< Unknown +} HiddbgHdlsNpadAssignment; + +/// HdlsStateList +typedef struct { + u8 unk_x0[0x408]; ///< Unknown +} HiddbgHdlsStateList; + +/// HdlsDeviceInfo +typedef struct { + u32 type; ///< See \ref HidControllerType, only one bit can be set. + u32 singleColorBody; ///< RGBA Single Body Color + u32 singleColorButtons; ///< RGBA Single Buttons Color + u8 unk_xc; ///< Unknown + u8 pad[0x3]; +} HiddbgHdlsDeviceInfo; + +/// HdlsState +typedef struct { + u8 unk_x0[0x8]; ///< Unknown + u32 unk_x8; ///< Unknown, written to HidController +0x419C. + u32 buttons; ///< See \ref HidControllerKeys. + JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition + u32 unused; ///< Unused +} HiddbgHdlsState; + +Result hiddbgInitialize(void); +void hiddbgExit(void); + +/// Initialize Hdls. Hdls is for virtual HID controllers. Only available with [7.0.0+]. +Result hiddbgAttachHdlsWorkBuffer(void); + +/// Exit Hdls, must be called at some point prior to hiddbgExit. Only available with [7.0.0+]. +Result hiddbgReleaseHdlsWorkBuffer(void); + +/// Gets state for \ref HiddbgHdlsNpadAssignment. Only available with [7.0.0+]. +Result hiddbgDumpHdlsNpadAssignmentState(HiddbgHdlsNpadAssignment *state); + +/// Gets state for \ref HiddbgHdlsStateList. Only available with [7.0.0+]. +Result hiddbgDumpHdlsStates(HiddbgHdlsStateList *state); + +/// Sets state for \ref HiddbgHdlsNpadAssignment. Only available with [7.0.0+]. +Result hiddbgApplyHdlsNpadAssignmentState(const HiddbgHdlsNpadAssignment *state, bool flag); + +/// Sets state for \ref HiddbgHdlsStateList. Only available with [7.0.0+]. +Result hiddbgApplyHdlsStateList(const HiddbgHdlsStateList *state); + +/// Attach a device with the input info, where the output handle is written to HdlsHandle. Only available with [7.0.0+]. +Result hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info); + +/// Detach the specified device. Only available with [7.0.0+]. +Result hiddbgDetachHdlsVirtualDevice(u64 HdlsHandle); + +/// Sets state for the specified device. Only available with [7.0.0+]. +Result hiddbgSetHdlsState(u64 HdlsHandle, const HiddbgHdlsState *state); + diff --git a/nx/source/services/hiddbg.c b/nx/source/services/hiddbg.c new file mode 100644 index 00000000..2aa8b797 --- /dev/null +++ b/nx/source/services/hiddbg.c @@ -0,0 +1,374 @@ +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/tmem.h" +#include "services/hiddbg.h" +#include "services/hid.h" +#include "services/sm.h" +#include "runtime/hosversion.h" + +static Service g_hiddbgSrv; +static u64 g_hiddbgRefCnt; + +static bool g_hiddbgHdlsInitialized; +static TransferMemory g_hiddbgHdlsTmem; + +Result hiddbgInitialize(void) { + atomicIncrement64(&g_hiddbgRefCnt); + + if (serviceIsActive(&g_hiddbgSrv)) + return 0; + + Result rc = smGetService(&g_hiddbgSrv, "hid:dbg"); + if (R_FAILED(rc)) + return rc; + + return 0; +} + +void hiddbgExit(void) { + if (atomicDecrement64(&g_hiddbgRefCnt) == 0) { + serviceClose(&g_hiddbgSrv); + } +} + +static Result _hiddbgCmdNoIO(u64 cmd_id) { + Result rc; + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _hiddbgCmdInU8NoOut(u64 cmd_id, u8 val) { + Result rc; + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u8 val; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->val = val; + + rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _hiddbgCmdInU64NoOut(u64 cmd_id, u64 val) { + Result rc; + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 val; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->val = val; + + rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _hiddbgAttachHdlsWorkBuffer(TransferMemory *tmem) { + IpcCommand c; + ipcInitialize(&c); + + ipcSendHandleCopy(&c, tmem->handle); + + struct { + u64 magic; + u64 cmd_id; + u64 size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 324; + raw->size = tmem->size; + + Result rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result hiddbgAttachHdlsWorkBuffer(void) { + Result rc=0; + + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); + + + rc = tmemCreate(&g_hiddbgHdlsTmem, 0x1000, Perm_Rw); + if (R_FAILED(rc)) return rc; + + rc = _hiddbgAttachHdlsWorkBuffer(&g_hiddbgHdlsTmem); + if (R_FAILED(rc)) tmemClose(&g_hiddbgHdlsTmem); + if (R_SUCCEEDED(rc)) g_hiddbgHdlsInitialized = true; + return rc; +} + +Result hiddbgReleaseHdlsWorkBuffer(void) { + Result rc=0; + + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + g_hiddbgHdlsInitialized = false; + + rc = _hiddbgCmdNoIO(325); + tmemClose(&g_hiddbgHdlsTmem); + return rc; +} + +Result hiddbgDumpHdlsNpadAssignmentState(HiddbgHdlsNpadAssignment *state) { + Result rc=0; + + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _hiddbgCmdNoIO(326); + if (R_FAILED(rc)) return rc; + if (state) memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state)); + return rc; +} + +Result hiddbgDumpHdlsStates(HiddbgHdlsStateList *state) { + Result rc=0; + + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _hiddbgCmdNoIO(327); + if (R_FAILED(rc)) return rc; + if (state) memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state)); + return rc; +} + +Result hiddbgApplyHdlsNpadAssignmentState(const HiddbgHdlsNpadAssignment *state, bool flag) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (state==NULL) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state)); + return _hiddbgCmdInU8NoOut(328, flag!=0); +} + +Result hiddbgApplyHdlsStateList(const HiddbgHdlsStateList *state) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (state==NULL) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state)); + return _hiddbgCmdNoIO(329); +} + +static Result _hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + HiddbgHdlsDeviceInfo info; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 330; + raw->info = *info; + + Result rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 handle; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && HdlsHandle) *HdlsHandle = resp->handle; + } + + return rc; +} + +Result hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _hiddbgAttachHdlsVirtualDevice(HdlsHandle, info); +} + +Result hiddbgDetachHdlsVirtualDevice(u64 HdlsHandle) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _hiddbgCmdInU64NoOut(331, HdlsHandle); +} + +static Result _hiddbgSetHdlsState(u64 HdlsHandle, const HiddbgHdlsState *state) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + HiddbgHdlsState state; + u64 handle; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 332; + memcpy(&raw->state, state, sizeof(*state)); + raw->handle = HdlsHandle; + + Result rc = serviceIpcDispatch(&g_hiddbgSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result hiddbgSetHdlsState(u64 HdlsHandle, const HiddbgHdlsState *state) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!g_hiddbgHdlsInitialized) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _hiddbgSetHdlsState(HdlsHandle, state); +} +