diff --git a/nx/include/switch/services/btm.h b/nx/include/switch/services/btm.h index 5a968127..bdb1c563 100644 --- a/nx/include/switch/services/btm.h +++ b/nx/include/switch/services/btm.h @@ -9,6 +9,41 @@ #include "../services/btdrv.h" #include "../sf/service.h" +/// HostDeviceProperty +typedef struct { + u8 unk_x0[0x2A]; ///< Unknown +} BtmHostDeviceProperty; + +/// DeviceCondition +typedef struct { + u8 unk_x0[0x368]; ///< Unknown +} BtmDeviceCondition; + +/// DeviceSlotModeList +typedef struct { + u8 unk_x0[0x64]; ///< Unknown +} BtmDeviceSlotModeList; + +/// DeviceInfoList +typedef struct { + u8 unk_x0[0x3C4]; ///< Unknown +} BtmDeviceInfoList; + +/// DeviceInfo +typedef struct { + u8 unk_x0[0x60]; ///< Unknown +} BtmDeviceInfo; + +/// DevicePropertyList +typedef struct { + u8 unk_x0[0x268]; ///< Unknown +} BtmDevicePropertyList; + +/// ZeroRetransmissionList +typedef struct { + u8 unk_x0[0x11]; ///< Unknown +} BtmZeroRetransmissionList; + /// GattClientConditionList typedef struct { u8 unk_x0[0x74]; ///< Unknown @@ -51,6 +86,157 @@ void btmExit(void); /// Gets the Service object for the actual btm service session. Service* btmGetServiceSession(void); +/** + * @brief GetState + * @param[out] out Output BtmState. + */ +Result btmGetState(u32 *out); + +/** + * @brief GetHostDeviceProperty + * @param[out] out \ref BtmHostDeviceProperty + */ +Result btmGetHostDeviceProperty(BtmHostDeviceProperty *out); + +/** + * @brief AcquireDeviceConditionEvent + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=true. + */ +Result btmAcquireDeviceConditionEvent(Event* out_event); + +/** + * @brief GetDeviceCondition + * @param[out] out \ref BtmDeviceCondition + */ +Result btmGetDeviceCondition(BtmDeviceCondition *out); + +/** + * @brief SetBurstMode + * @param[in] addr \ref BtdrvAddress + * @param[in] flag Flag + */ +Result btmSetBurstMode(BtdrvAddress addr, bool flag); + +/** + * @brief SetSlotMode + * @param[in] list \ref BtmDeviceSlotModeList + */ +Result btmSetSlotMode(const BtmDeviceSlotModeList *list); + +/** + * @brief SetBluetoothMode + * @note Only available on pre-9.0.0. + * @param[in] mode BluetoothMode + */ +Result btmSetBluetoothMode(u32 mode); + +/** + * @brief SetWlanMode + * @param[in] mode WlanMode + */ +Result btmSetWlanMode(u32 mode); + +/** + * @brief AcquireDeviceInfoEvent + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=true. + */ +Result btmAcquireDeviceInfoEvent(Event* out_event); + +/** + * @brief GetDeviceInfo + * @param[out] out \ref BtmDeviceInfoList + */ +Result btmGetDeviceInfo(BtmDeviceInfoList *out); + +/** + * @brief AddDeviceInfo + * @param[in] info \ref BtmDeviceInfo + */ +Result btmAddDeviceInfo(const BtmDeviceInfo *info); + +/** + * @brief RemoveDeviceInfo + * @param[in] addr \ref BtdrvAddress + */ +Result btmRemoveDeviceInfo(BtdrvAddress addr); + +/** + * @brief IncreaseDeviceInfoOrder + * @param[in] addr \ref BtdrvAddress + */ +Result btmIncreaseDeviceInfoOrder(BtdrvAddress addr); + +/** + * @brief LlrNotify + * @param[in] addr \ref BtdrvAddress + * @param[in] unk [9.0.0+] Unknown + */ +Result btmLlrNotify(BtdrvAddress addr, s32 unk); + +/** + * @brief EnableRadio + */ +Result btmEnableRadio(void); + +/** + * @brief DisableRadio + */ +Result btmDisableRadio(void); + +/** + * @brief HidDisconnect + * @param[in] addr \ref BtdrvAddress + */ +Result btmHidDisconnect(BtdrvAddress addr); + +/** + * @brief HidSetRetransmissionMode + * @param[in] addr \ref BtdrvAddress + * @param[in] list \ref BtmZeroRetransmissionList + */ +Result btmHidSetRetransmissionMode(BtdrvAddress addr, const BtmZeroRetransmissionList *list); + +/** + * @brief AcquireAwakeReqEvent + * @note Only available on [2.0.0+]. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=true. + */ +Result btmAcquireAwakeReqEvent(Event* out_event); + + +/** + * @brief AcquireLlrStateEvent + * @note Only available on [4.0.0+]. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=true. + */ +Result btmAcquireLlrStateEvent(Event* out_event); + +/** + * @brief IsLlrStarted + * @note Only available on [4.0.0+]. + * @param[out] out Output flag. + */ +Result btmIsLlrStarted(bool *out); + +/** + * @brief EnableSlotSaving + * @note Only available on [4.0.0+]. + * @param[in] flag Flag + */ +Result btmEnableSlotSaving(bool flag); + +/** + * @brief ProtectDeviceInfo + * @note Only available on [5.0.0+]. + * @param[in] addr \ref BtdrvAddress + * @param[in] flag Flag + */ +Result btmProtectDeviceInfo(BtdrvAddress addr, bool flag); + /** * @brief AcquireBleScanEvent * @note Only available on [5.0.0+]. diff --git a/nx/source/services/btm.c b/nx/source/services/btm.c index c92928e5..db609593 100644 --- a/nx/source/services/btm.c +++ b/nx/source/services/btm.c @@ -46,14 +46,64 @@ static Result _btmCmdGetEventOutFlag(Event* out_event, bool autoclear, u32 cmd_i return rc; } +static Result _btmCmdInU8NoOut(u8 inval, u64 cmd_id) { + return serviceDispatchIn(&g_btmSrv, cmd_id, inval); +} + +static Result _btmCmdInBoolNoOut(bool inval, u32 cmd_id) { + return _btmCmdInU8NoOut(inval!=0, cmd_id); +} + static Result _btmCmdInU32NoOut(u32 inval, u32 cmd_id) { return serviceDispatchIn(&g_btmSrv, cmd_id, inval); } +static Result _btmCmdNoInOutU8(u8 *out, u32 cmd_id) { + return serviceDispatchOut(&g_btmSrv, cmd_id, *out); +} + +static Result _btmCmdNoInOutBool(bool *out, u32 cmd_id) { + u8 tmp=0; + Result rc = _btmCmdNoInOutU8(&tmp, cmd_id); + if (R_SUCCEEDED(rc) && out) *out = tmp & 1; + return rc; +} + +static Result _btmCmdNoInOutU32(u32 *out, u32 cmd_id) { + return serviceDispatchOut(&g_btmSrv, cmd_id, *out); +} + +static Result _btmCmdInAddrNoOut(BtdrvAddress addr, u32 cmd_id) { + return serviceDispatchIn(&g_btmSrv, cmd_id, addr); +} + +static Result _btmCmdInAddrBoolNoOut(BtdrvAddress addr, bool flag, u32 cmd_id) { + const struct { + BtdrvAddress addr; + u8 flag; + } in = { addr, flag!=0 }; + + return serviceDispatchIn(&g_btmSrv, cmd_id, in); +} + static Result _btmCmdInBleAdvertisePacketParameterNoOut(BtdrvBleAdvertisePacketParameter param, u32 cmd_id) { return serviceDispatchIn(&g_btmSrv, cmd_id, param); } +static Result _btmCmdInBufPtrFixed(const void* buffer, size_t size, u32 cmd_id) { + return serviceDispatch(&g_btmSrv, cmd_id, + .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In | SfBufferAttr_FixedSize }, + .buffers = { { buffer, size } }, + ); +} + +static Result _btmCmdOutBufPtrFixed(void* buffer, size_t size, u32 cmd_id) { + return serviceDispatch(&g_btmSrv, cmd_id, + .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out | SfBufferAttr_FixedSize }, + .buffers = { { buffer, size } }, + ); +} + static Result _btmGetBleScanResults(BtdrvBleScanResult *results, u8 count, u8 *total_out, u32 cmd_id) { return serviceDispatchOut(&g_btmSrv, cmd_id, *total_out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, @@ -87,6 +137,128 @@ static Result _btmRegisterBleGattDataPath(const BtmBleDataPath *path, u32 cmd_id return serviceDispatchIn(&g_btmSrv, cmd_id, *path); } +Result btmGetState(u32 *out) { + return _btmCmdNoInOutU32(out, 0); +} + +Result btmGetHostDeviceProperty(BtmHostDeviceProperty *out) { + return serviceDispatchOut(&g_btmSrv, 1, *out); +} + +Result btmAcquireDeviceConditionEvent(Event* out_event) { + return _btmCmdGetEventOutFlag(out_event, true, 2); +} + +Result btmGetDeviceCondition(BtmDeviceCondition *out) { + return _btmCmdOutBufPtrFixed(out, sizeof(*out), 3); +} + +Result btmSetBurstMode(BtdrvAddress addr, bool flag) { + return _btmCmdInAddrBoolNoOut(addr, flag, 4); +} + +Result btmSetSlotMode(const BtmDeviceSlotModeList *list) { + return _btmCmdInBufPtrFixed(list, sizeof(*list), 5); +} + +Result btmSetBluetoothMode(u32 mode) { + if (hosversionAtLeast(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInU32NoOut(mode, 6); +} + +Result btmSetWlanMode(u32 mode) { + return _btmCmdInU32NoOut(mode, 7); +} + +Result btmAcquireDeviceInfoEvent(Event* out_event) { + return _btmCmdGetEventOutFlag(out_event, true, 8); +} + +Result btmGetDeviceInfo(BtmDeviceInfoList *out) { + return _btmCmdOutBufPtrFixed(out, sizeof(*out), 9); +} + +Result btmAddDeviceInfo(const BtmDeviceInfo *info) { + return serviceDispatchIn(&g_btmSrv, 10, *info); +} + +Result btmRemoveDeviceInfo(BtdrvAddress addr) { + return _btmCmdInAddrNoOut(addr, 11); +} + +Result btmIncreaseDeviceInfoOrder(BtdrvAddress addr) { + return _btmCmdInAddrNoOut(addr, 12); +} + +Result btmLlrNotify(BtdrvAddress addr, s32 unk) { + if (hosversionBefore(9,0,0)) + return _btmCmdInAddrNoOut(addr, 13); + + const struct { + BtdrvAddress addr; + u8 pad[2]; + s32 unk; + } in = { addr, {0}, unk }; + + return serviceDispatchIn(&g_btmSrv, 13, in); +} + +Result btmEnableRadio(void) { + return _btmCmdNoIO(14); +} + +Result btmDisableRadio(void) { + return _btmCmdNoIO(15); +} + +Result btmHidDisconnect(BtdrvAddress addr) { + return _btmCmdInAddrNoOut(addr, 16); +} + +Result btmHidSetRetransmissionMode(BtdrvAddress addr, const BtmZeroRetransmissionList *list) { + return serviceDispatchIn(&g_btmSrv, 17, addr, + .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In | SfBufferAttr_FixedSize }, + .buffers = { { list, sizeof(*list) } }, + ); +} + +Result btmAcquireAwakeReqEvent(Event* out_event) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdGetEventOutFlag(out_event, true, 18); +} + +Result btmAcquireLlrStateEvent(Event* out_event) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdGetEventOutFlag(out_event, true, 19); +} + +Result btmIsLlrStarted(bool *out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdNoInOutBool(out, 20); +} + +Result btmEnableSlotSaving(bool flag) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInBoolNoOut(flag, 21); +} + +Result btmProtectDeviceInfo(BtdrvAddress addr, bool flag) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInAddrBoolNoOut(addr, flag, 22); +} + Result btmAcquireBleScanEvent(Event* out_event) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);