From eadd2e0a6c45089e242e03fc4dc7e9108db17b04 Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Mon, 28 Sep 2026 09:39:07 +0200 Subject: [PATCH 1/5] btm: adjust device condition/info struct names to match wiki --- nx/include/switch/services/btm.h | 8 ++--- nx/include/switch/services/btm_types.h | 44 +++++++++++++------------- nx/source/services/btm.c | 14 ++++---- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/nx/include/switch/services/btm.h b/nx/include/switch/services/btm.h index 8db496e315..3913c81a04 100644 --- a/nx/include/switch/services/btm.h +++ b/nx/include/switch/services/btm.h @@ -41,18 +41,18 @@ Result btmAcquireDeviceConditionEvent(Event* out_event); /** * @brief GetDeviceCondition [1.0.0-12.1.0] - * @param[out] out \ref BtmDeviceCondition + * @param[out] out \ref BtmDeviceConditionList */ -Result btmLegacyGetDeviceCondition(BtmDeviceCondition *out); +Result btmLegacyGetDeviceCondition(BtmDeviceConditionList *out); /** * @brief GetDeviceCondition [13.0.0+] * @param[in] profile \ref BtmProfile, when not ::BtmProfile_None entries are only returned which match this profile. - * @param[out] out \ref BtmConnectedDeviceV13 + * @param[out] out \ref BtmDeviceConditionV13 * @param[in] count Size of the out array in entries. * @param[out] total_out Total output entries. */ -Result btmGetDeviceCondition(BtmProfile profile, BtmConnectedDeviceV13 *out, size_t count, s32 *total_out); +Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceConditionV13 *out, size_t count, s32 *total_out); /** * @brief SetBurstMode diff --git a/nx/include/switch/services/btm_types.h b/nx/include/switch/services/btm_types.h index 46ceeac435..9ab66d01d2 100644 --- a/nx/include/switch/services/btm_types.h +++ b/nx/include/switch/services/btm_types.h @@ -103,7 +103,7 @@ typedef struct { }; } BtmHostDeviceProperty; -/// BtmConnectedDevice [1.0.0-12.1.0] +/// DeviceCondition [1.0.0-12.1.0] typedef struct { BtdrvAddress address; u8 pad[2]; @@ -113,9 +113,9 @@ typedef struct { u16 vid; u16 pid; u8 unk_x4C[0x20]; -} BtmConnectedDeviceV1; +} BtmDeviceConditionV1; -/// BtmConnectedDevice [13.0.0+] +/// DeviceCondition [13.0.0+] typedef struct { BtdrvAddress address; u8 pad[2]; @@ -124,9 +124,9 @@ typedef struct { char name[0x20]; u8 unk_x6C[0xD9]; u8 pad2[3]; -} BtmConnectedDeviceV13; +} BtmDeviceConditionV13; -/// DeviceCondition [1.0.0-5.0.2] +/// DeviceConditionList [1.0.0-5.0.2] typedef struct { u32 unk_x0; u32 unk_x4; @@ -134,10 +134,10 @@ typedef struct { u8 unk_x9; u8 max_count; u8 connected_count; - BtmConnectedDeviceV1 devices[8]; -} BtmDeviceConditionV100; + BtmDeviceConditionV1 devices[8]; +} BtmDeviceConditionListV100; -/// DeviceCondition [5.1.0-7.0.1] +/// DeviceConditionList [5.1.0-7.0.1] typedef struct { u32 unk_x0; u32 unk_x4; @@ -146,10 +146,10 @@ typedef struct { u8 max_count; u8 connected_count; u8 pad[3]; - BtmConnectedDeviceV1 devices[8]; -} BtmDeviceConditionV510; + BtmDeviceConditionV1 devices[8]; +} BtmDeviceConditionListV510; -/// DeviceCondition [8.0.0-8.1.1] +/// DeviceConditionList [8.0.0-8.1.1] typedef struct { u32 unk_x0; u32 unk_x4; @@ -157,26 +157,26 @@ typedef struct { u8 unk_x9; u8 max_count; u8 connected_count; - BtmConnectedDeviceV1 devices[8]; -} BtmDeviceConditionV800; + BtmDeviceConditionV1 devices[8]; +} BtmDeviceConditionListV800; -/// DeviceCondition [9.0.0-12.1.0] +/// DeviceConditionList [9.0.0-12.1.0] typedef struct { u32 unk_x0; u8 unk_x4; u8 unk_x5; u8 max_count; u8 connected_count; - BtmConnectedDeviceV1 devices[8]; -} BtmDeviceConditionV900; + BtmDeviceConditionV1 devices[8]; +} BtmDeviceConditionListV900; -/// DeviceCondition [1.0.0-12.1.0] +/// DeviceConditionList [1.0.0-12.1.0] typedef union { - BtmDeviceConditionV100 v100; - BtmDeviceConditionV510 v510; - BtmDeviceConditionV800 v800; - BtmDeviceConditionV900 v900; -} BtmDeviceCondition; + BtmDeviceConditionListV100 v100; + BtmDeviceConditionListV510 v510; + BtmDeviceConditionListV800 v800; + BtmDeviceConditionListV900 v900; +} BtmDeviceConditionList; /// DeviceSlotMode typedef struct { diff --git a/nx/source/services/btm.c b/nx/source/services/btm.c index ae8c10c706..d35c9f5495 100644 --- a/nx/source/services/btm.c +++ b/nx/source/services/btm.c @@ -166,23 +166,23 @@ Result btmAcquireDeviceConditionEvent(Event* out_event) { return _btmCmdGetEventOutFlag(out_event, true, 2); } -Result btmLegacyGetDeviceCondition(BtmDeviceCondition *out) { +Result btmLegacyGetDeviceCondition(BtmDeviceConditionList *out) { if (hosversionAtLeast(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); size_t buff_size; - if (hosversionAtLeast(9,0,0)) buff_size = sizeof(BtmDeviceConditionV900); - else if (hosversionAtLeast(8,0,0)) buff_size = sizeof(BtmDeviceConditionV800); - else if (hosversionAtLeast(5,1,0)) buff_size = sizeof(BtmDeviceConditionV510); - else buff_size = sizeof(BtmDeviceConditionV100); + if (hosversionAtLeast(9,0,0)) buff_size = sizeof(BtmDeviceConditionListV900); + else if (hosversionAtLeast(8,0,0)) buff_size = sizeof(BtmDeviceConditionListV800); + else if (hosversionAtLeast(5,1,0)) buff_size = sizeof(BtmDeviceConditionListV510); + else buff_size = sizeof(BtmDeviceConditionListV100); return _btmCmdOutBufPtrFixed(out, buff_size, 3); } -Result btmGetDeviceCondition(BtmProfile profile, BtmConnectedDeviceV13 *out, size_t count, s32 *total_out) { +Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceConditionV13 *out, size_t count, s32 *total_out) { if (hosversionBefore(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmConnectedDeviceV13)*count, total_out, 3); + return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmDeviceConditionV13)*count, total_out, 3); } Result btmSetBurstMode(BtdrvAddress addr, bool flag) { From 1c448addc51fc3afa155363d4956ca3c1ae87692 Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Mon, 28 Sep 2026 10:03:26 +0200 Subject: [PATCH 2/5] btm: add key type field to 13.0.0 device info struct --- nx/include/switch/services/btm_types.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nx/include/switch/services/btm_types.h b/nx/include/switch/services/btm_types.h index 9ab66d01d2..0dff52d05c 100644 --- a/nx/include/switch/services/btm_types.h +++ b/nx/include/switch/services/btm_types.h @@ -212,7 +212,8 @@ typedef struct { BtdrvAddress addr; ///< \ref BtdrvAddress BtmClassOfDevice class_of_device; ///< ClassOfDevice BtmLinkKey link_key; ///< LinkKey - u8 reserved[3]; ///< Reserved + u8 key_type; ///< KeyType + u8 reserved[2]; ///< Reserved u32 profile; ///< \ref BtmProfile union { u8 data[0x4]; ///< Empty (Profile = None) From f5ec3637c16306e3a9b52e310de537143fd0701b Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:20:42 +0200 Subject: [PATCH 3/5] btm: update device condition/info structures and fill missing fields --- nx/include/switch/services/btm_types.h | 161 ++++++++++++++++--------- 1 file changed, 105 insertions(+), 56 deletions(-) diff --git a/nx/include/switch/services/btm_types.h b/nx/include/switch/services/btm_types.h index 0dff52d05c..557d30ef6c 100644 --- a/nx/include/switch/services/btm_types.h +++ b/nx/include/switch/services/btm_types.h @@ -48,6 +48,13 @@ typedef enum { BtmTsiMode_Active = 255, ///< Active } BtmTsiMode; +typedef enum { + BtmSniffMode_5ms = 0, ///< 5ms + BtmSniffMode_10ms = 1, ///< 10ms + BtmSniffMode_15ms = 2, ///< 15ms + BtmSniffMode_Active = 3, ///< Active +} BtmSniffMode; + /// SlotMode typedef enum { BtmSlotMode_2 = 0, ///< 2 @@ -78,12 +85,55 @@ typedef struct { u8 link_key[0x10]; ///< LinkKey } BtmLinkKey; +/// ZeroRetransmissionList +typedef struct { + u8 enabled_report_id_count; ///< EnabledReportIdCount + u8 enabled_report_id[0x10]; ///< Array of EnabledReportId. +} BtmZeroRetransmissionList; + +/// HidDeviceCondition +typedef struct { + u32 sniff_mode; ///< \ref BtmSniffMode + u32 slot_mode; ///< \ref BtmSlotMode + bool is_burst_mode; ///< IsBurstMode + BtmZeroRetransmissionList zero_retransmission_list; ///< \ref BtmZeroRetransmissionList + u16 vid; ///< Vid + u16 pid; ///< Pid +} BtmHidDeviceCondition; + +/// AudioDeviceCondition [13.0.0+] +typedef struct { + u8 unk_x0; ///< Unknown +} BtmAudioDeviceCondition; + /// HidDeviceInfo typedef struct { - u16 vid; ///< Vid - u16 pid; ///< Pid + u16 vid; ///< Vid + u16 pid; ///< Pid } BtmHidDeviceInfo; +/// AudioDeviceInfo [13.0.0+] +typedef struct { + union { + struct { + u8 source_volume; ///< SourceVolume + } v13; ///< [13.0.0-13.2.1] + + struct { + u8 source_volume; ///< SourceVolume + bool is_first_audio_control_connection; ///< IsFirstAudioControlConnection + u8 unk_0x2; ///< Unknown + } v14; ///< [14.0.0-14.1.2] + + struct { + u8 source_volume; ///< SourceVolume + u8 sink_volume; ///< SinkVolume + bool is_first_audio_control_connection; ///< IsFirstAudioControlConnection + bool unk_0x3; ///< Unknown + } v15; ///< [15.0.0+] + }; +} BtmAudioDeviceInfo; + /// HostDeviceProperty typedef struct { union { @@ -105,69 +155,75 @@ typedef struct { /// DeviceCondition [1.0.0-12.1.0] typedef struct { - BtdrvAddress address; - u8 pad[2]; - u32 unk_x8; - char name[0x20]; - u8 unk_x2C[0x1C]; - u16 vid; - u16 pid; - u8 unk_x4C[0x20]; + BtdrvAddress address; ///< \ref BtdrvAddress + u8 pad[2]; ///< Padding + u32 profile; ///< \ref BtmProfile + char name[0x20]; ///< BdName + union { + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceCondition hid; ///< \ref BtmHidDeviceCondition (Profile = Hid) + } profile_condition; + u8 reserved[0x20]; ///< Reserved } BtmDeviceConditionV1; /// DeviceCondition [13.0.0+] typedef struct { - BtdrvAddress address; - u8 pad[2]; + BtdrvAddress address; ///< \ref BtdrvAddress + u8 pad[2]; ///< Padding u32 profile; ///< \ref BtmProfile - u8 unk_xC[0x40]; - char name[0x20]; - u8 unk_x6C[0xD9]; - u8 pad2[3]; + union { + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceCondition hid; ///< \ref BtmHidDeviceCondition (Profile = Hid) + BtmAudioDeviceCondition audio; ///< \ref BtmAudioDeviceCondition (Profile = Audio) + } profile_condition; + u8 reserved[0x20]; ///< Reserved + char name[0xF9]; ///< Name + u8 pad2[3]; ///< Padding } BtmDeviceConditionV13; /// DeviceConditionList [1.0.0-5.0.2] typedef struct { - u32 unk_x0; - u32 unk_x4; - u8 unk_x8; - u8 unk_x9; - u8 max_count; - u8 connected_count; - BtmDeviceConditionV1 devices[8]; + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. } BtmDeviceConditionListV100; /// DeviceConditionList [5.1.0-7.0.1] typedef struct { - u32 unk_x0; - u32 unk_x4; - u8 unk_x8; - u8 unk_x9[2]; - u8 max_count; - u8 connected_count; - u8 pad[3]; - BtmDeviceConditionV1 devices[8]; + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 unk_0xA; ///< Unknown + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + u8 pad[3]; ///< Padding + BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. } BtmDeviceConditionListV510; /// DeviceConditionList [8.0.0-8.1.1] typedef struct { - u32 unk_x0; - u32 unk_x4; - u8 unk_x8; - u8 unk_x9; - u8 max_count; - u8 connected_count; - BtmDeviceConditionV1 devices[8]; + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. } BtmDeviceConditionListV800; /// DeviceConditionList [9.0.0-12.1.0] typedef struct { - u32 unk_x0; - u8 unk_x4; - u8 unk_x5; - u8 max_count; - u8 connected_count; - BtmDeviceConditionV1 devices[8]; + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. } BtmDeviceConditionListV900; /// DeviceConditionList [1.0.0-12.1.0] @@ -201,10 +257,9 @@ typedef struct { u8 reserved[3]; ///< Reserved u32 profile; ///< \ref BtmProfile union { - u8 data[0x4]; ///< Empty (Profile = None) - BtmHidDeviceInfo hid_device_info; ///< \ref BtmHidDeviceInfo (Profile = Hid) + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceInfo hid; ///< \ref BtmHidDeviceInfo (Profile = Hid) } profile_info; - u8 reserved2[0x1C]; ///< Reserved } BtmDeviceInfoV1; /// DeviceInfo [13.0.0+] @@ -216,10 +271,10 @@ typedef struct { u8 reserved[2]; ///< Reserved u32 profile; ///< \ref BtmProfile union { - u8 data[0x4]; ///< Empty (Profile = None) - BtmHidDeviceInfo hid_device_info; ///< \ref BtmHidDeviceInfo (Profile = Hid) + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceInfo hid; ///< \ref BtmHidDeviceInfo (Profile = Hid) + BtmAudioDeviceInfo audio; ///< \ref BtmAudioDeviceInfo (Profile = Audio) } profile_info; - u8 reserved2[0x1C]; ///< Reserved char name[0xF9]; ///< Name u8 pad[3]; ///< Padding } BtmDeviceInfoV13; @@ -250,12 +305,6 @@ typedef struct { BtmDeviceProperty devices[15]; ///< Array of \ref BtmDeviceProperty. } BtmDevicePropertyList; -/// ZeroRetransmissionList -typedef struct { - u8 enabled_report_id_count; ///< EnabledReportIdCount - u8 enabled_report_id[0x10]; ///< Array of EnabledReportId. -} BtmZeroRetransmissionList; - /// GattClientConditionList typedef struct { u8 unk_x0[0x74]; ///< Unknown From 8864c36cc611e1651a440ec903a7009c26fe891e Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:32:07 +0200 Subject: [PATCH 4/5] btm: simplify version specific struct naming --- nx/include/switch/services/btm.h | 16 ++++-- nx/include/switch/services/btm_types.h | 76 ++++++++++++-------------- nx/source/services/btm.c | 19 +++++-- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/nx/include/switch/services/btm.h b/nx/include/switch/services/btm.h index 3913c81a04..c5ed765617 100644 --- a/nx/include/switch/services/btm.h +++ b/nx/include/switch/services/btm.h @@ -48,11 +48,11 @@ Result btmLegacyGetDeviceCondition(BtmDeviceConditionList *out); /** * @brief GetDeviceCondition [13.0.0+] * @param[in] profile \ref BtmProfile, when not ::BtmProfile_None entries are only returned which match this profile. - * @param[out] out \ref BtmDeviceConditionV13 + * @param[out] out \ref BtmDeviceCondition * @param[in] count Size of the out array in entries. * @param[out] total_out Total output entries. */ -Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceConditionV13 *out, size_t count, s32 *total_out); +Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceCondition *out, size_t count, s32 *total_out); /** * @brief SetBurstMode @@ -96,14 +96,20 @@ Result btmLegacyGetDeviceInfo(BtmDeviceInfoList *out); /** * @brief GetDeviceInfo [13.0.0+] * @param[in] profile \ref BtmProfile, when not ::BtmProfile_None entries are only returned which match this profile. - * @param[out] out \ref BtmDeviceInfoV13 + * @param[out] out \ref BtmDeviceInfo * @param[in] count Size of the out array in entries. * @param[out] total_out Total output entries. */ -Result btmGetDeviceInfo(BtmProfile profile, BtmDeviceInfoV13 *out, size_t count, s32 *total_out); +Result btmGetDeviceInfo(BtmProfile profile, BtmDeviceInfo *out, size_t count, s32 *total_out); /** - * @brief AddDeviceInfo + * @brief AddDeviceInfo [1.0.0-12.1.0] + * @param[in] info \ref BtmDeviceInfo + */ +Result btmLegacyAddDeviceInfo(const BtmDeviceInfoLegacy *info); + +/** + * @brief AddDeviceInfo [13.0.0+] * @param[in] info \ref BtmDeviceInfo */ Result btmAddDeviceInfo(const BtmDeviceInfo *info); diff --git a/nx/include/switch/services/btm_types.h b/nx/include/switch/services/btm_types.h index 557d30ef6c..9b91fcbfb9 100644 --- a/nx/include/switch/services/btm_types.h +++ b/nx/include/switch/services/btm_types.h @@ -164,7 +164,7 @@ typedef struct { BtmHidDeviceCondition hid; ///< \ref BtmHidDeviceCondition (Profile = Hid) } profile_condition; u8 reserved[0x20]; ///< Reserved -} BtmDeviceConditionV1; +} BtmDeviceConditionLegacy; /// DeviceCondition [13.0.0+] typedef struct { @@ -179,51 +179,51 @@ typedef struct { u8 reserved[0x20]; ///< Reserved char name[0xF9]; ///< Name u8 pad2[3]; ///< Padding -} BtmDeviceConditionV13; +} BtmDeviceCondition; /// DeviceConditionList [1.0.0-5.0.2] typedef struct { - u32 bluetooth_mode; ///< \ref BtmBluetoothMode - u32 wlan_mode; ///< \ref BtmWlanMode - bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing - bool is_slot_saving; ///< IsSlotSaving - u8 connection_capacity; ///< ConnectionCapacity - u8 device_count; ///< DeviceCount - BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionLegacy devices[8]; ///< Array of \ref BtmDeviceConditionLegacy with the above count. } BtmDeviceConditionListV100; /// DeviceConditionList [5.1.0-7.0.1] typedef struct { - u32 bluetooth_mode; ///< \ref BtmBluetoothMode - u32 wlan_mode; ///< \ref BtmWlanMode - bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing - bool is_slot_saving; ///< IsSlotSaving - u8 unk_0xA; ///< Unknown - u8 connection_capacity; ///< ConnectionCapacity - u8 device_count; ///< DeviceCount - u8 pad[3]; ///< Padding - BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 unk_0xA; ///< Unknown + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + u8 pad[3]; ///< Padding + BtmDeviceConditionLegacy devices[8]; ///< Array of \ref BtmDeviceConditionLegacy with the above count. } BtmDeviceConditionListV510; /// DeviceConditionList [8.0.0-8.1.1] typedef struct { - u32 bluetooth_mode; ///< \ref BtmBluetoothMode - u32 wlan_mode; ///< \ref BtmWlanMode - bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing - bool is_slot_saving; ///< IsSlotSaving - u8 connection_capacity; ///< ConnectionCapacity - u8 device_count; ///< DeviceCount - BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. + u32 bluetooth_mode; ///< \ref BtmBluetoothMode + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionLegacy devices[8]; ///< Array of \ref BtmDeviceConditionLegacy with the above count. } BtmDeviceConditionListV800; /// DeviceConditionList [9.0.0-12.1.0] typedef struct { - u32 wlan_mode; ///< \ref BtmWlanMode - bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing - bool is_slot_saving; ///< IsSlotSaving - u8 connection_capacity; ///< ConnectionCapacity - u8 device_count; ///< DeviceCount - BtmDeviceConditionV1 devices[8]; ///< Array of \ref BtmDeviceConditionV1 with the above count. + u32 wlan_mode; ///< \ref BtmWlanMode + bool is_slot_saving_for_pairing; ///< IsSlotSavingForPairing + bool is_slot_saving; ///< IsSlotSaving + u8 connection_capacity; ///< ConnectionCapacity + u8 device_count; ///< DeviceCount + BtmDeviceConditionLegacy devices[8]; ///< Array of \ref BtmDeviceConditionLegacy with the above count. } BtmDeviceConditionListV900; /// DeviceConditionList [1.0.0-12.1.0] @@ -260,7 +260,7 @@ typedef struct { u8 data[0x20]; ///< Empty (Profile = None) BtmHidDeviceInfo hid; ///< \ref BtmHidDeviceInfo (Profile = Hid) } profile_info; -} BtmDeviceInfoV1; +} BtmDeviceInfoLegacy; /// DeviceInfo [13.0.0+] typedef struct { @@ -277,19 +277,13 @@ typedef struct { } profile_info; char name[0xF9]; ///< Name u8 pad[3]; ///< Padding -} BtmDeviceInfoV13; - -/// DeviceInfo [1.0.0-13.0.0] -typedef union { - BtmDeviceInfoV1 v1; - BtmDeviceInfoV13 v13; } BtmDeviceInfo; /// DeviceInfoList typedef struct { - u8 device_count; ///< DeviceCount - u8 reserved[3]; ///< Reserved - BtmDeviceInfoV1 devices[10]; ///< Array of \ref BtmDeviceInfoV1 with the above count. + u8 device_count; ///< DeviceCount + u8 reserved[3]; ///< Reserved + BtmDeviceInfoLegacy devices[10]; ///< Array of \ref BtmDeviceInfoLegacy with the above count. } BtmDeviceInfoList; /// DeviceProperty diff --git a/nx/source/services/btm.c b/nx/source/services/btm.c index d35c9f5495..8e656fef08 100644 --- a/nx/source/services/btm.c +++ b/nx/source/services/btm.c @@ -178,11 +178,11 @@ Result btmLegacyGetDeviceCondition(BtmDeviceConditionList *out) { return _btmCmdOutBufPtrFixed(out, buff_size, 3); } -Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceConditionV13 *out, size_t count, s32 *total_out) { +Result btmGetDeviceCondition(BtmProfile profile, BtmDeviceCondition *out, size_t count, s32 *total_out) { if (hosversionBefore(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmDeviceConditionV13)*count, total_out, 3); + return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmDeviceCondition)*count, total_out, 3); } Result btmSetBurstMode(BtdrvAddress addr, bool flag) { @@ -215,18 +215,25 @@ Result btmLegacyGetDeviceInfo(BtmDeviceInfoList *out) { return _btmCmdOutBufPtrFixed(out, sizeof(*out), 9); } -Result btmGetDeviceInfo(BtmProfile profile, BtmDeviceInfoV13 *out, size_t count, s32 *total_out) { +Result btmGetDeviceInfo(BtmProfile profile, BtmDeviceInfo *out, size_t count, s32 *total_out) { if (hosversionBefore(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmDeviceInfoV13)*count, total_out, 9); + return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmDeviceInfo)*count, total_out, 9); +} + +Result btmLegacyAddDeviceInfo(const BtmDeviceInfoLegacy *info) { + if (hosversionAtLeast(13,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInBufPtrFixed(info, sizeof((*info)), 10); } Result btmAddDeviceInfo(const BtmDeviceInfo *info) { if (hosversionBefore(13,0,0)) - return serviceDispatchIn(&g_btmSrv, 10, (*info).v1); + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _btmCmdInBufPtrFixed(info, sizeof((*info).v13), 10); + return _btmCmdInBufPtrFixed(info, sizeof((*info)), 10); } Result btmRemoveDeviceInfo(BtdrvAddress addr) { From 51a7ce30175cda7437451eb544936fb8a938c874 Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:33:19 +0200 Subject: [PATCH 5/5] btm: add commands for retrieving shortened versions of device condition/info --- nx/include/switch/services/btm.h | 19 +++++++++++++++ nx/include/switch/services/btm_types.h | 32 ++++++++++++++++++++++++++ nx/source/services/btm.c | 13 +++++++++++ 3 files changed, 64 insertions(+) diff --git a/nx/include/switch/services/btm.h b/nx/include/switch/services/btm.h index c5ed765617..978b5faacd 100644 --- a/nx/include/switch/services/btm.h +++ b/nx/include/switch/services/btm.h @@ -495,3 +495,22 @@ Result btmUnregisterAppletResourceUserId(u64 AppletResourceUserId); */ Result btmSetAppletResourceUserId(u64 AppletResourceUserId); +/** + * @brief GetShortenedDeviceInfo + * @note Only available on [13.0.0+]. + * @param[in] profile \ref BtmProfile, when not ::BtmProfile_None entries are only returned which match this profile. + * @param[out] out \ref BtmShortenedDeviceInfo + * @param[in] count Size of the out array in entries. + * @param[out] total_out Total output entries. + */ +Result btmGetShortenedDeviceInfo(BtmProfile profile, BtmShortenedDeviceInfo *out, size_t count, s32 *total_out); + +/** + * @brief GetShortenedDeviceCondition + * @note Only available on [14.0.0+]. + * @param[in] profile \ref BtmProfile, when not ::BtmProfile_None entries are only returned which match this profile. + * @param[out] out \ref BtmShortenedDeviceCondition + * @param[in] count Size of the out array in entries. + * @param[out] total_out Total output entries. + */ +Result btmGetShortenedDeviceCondition(BtmProfile profile, BtmShortenedDeviceCondition *out, size_t count, s32 *total_out); diff --git a/nx/include/switch/services/btm_types.h b/nx/include/switch/services/btm_types.h index 9b91fcbfb9..5285f53079 100644 --- a/nx/include/switch/services/btm_types.h +++ b/nx/include/switch/services/btm_types.h @@ -181,6 +181,21 @@ typedef struct { u8 pad2[3]; ///< Padding } BtmDeviceCondition; +/// ShortenedDeviceCondition [14.0.0+] +typedef struct { + BtdrvAddress address; ///< \ref BtdrvAddress + u8 pad[2]; ///< Padding + u32 profile; ///< \ref BtmProfile + union { + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceCondition hid; ///< \ref BtmHidDeviceCondition (Profile = Hid) + BtmAudioDeviceCondition audio; ///< \ref BtmAudioDeviceCondition (Profile = Audio) + } profile_condition; + u8 reserved[0x20]; ///< Reserved + char name[0x15]; ///< Name + u8 pad2[3]; ///< Padding +} BtmShortenedDeviceCondition; + /// DeviceConditionList [1.0.0-5.0.2] typedef struct { u32 bluetooth_mode; ///< \ref BtmBluetoothMode @@ -279,6 +294,23 @@ typedef struct { u8 pad[3]; ///< Padding } BtmDeviceInfo; +/// ShortenedDeviceInfo [13.0.0+] +typedef struct { + BtdrvAddress addr; ///< \ref BtdrvAddress + BtmClassOfDevice class_of_device; ///< ClassOfDevice + BtmLinkKey link_key; ///< LinkKey + u8 key_type; ///< KeyType + u8 reserved[2]; ///< Reserved + u32 profile; ///< \ref BtmProfile + union { + u8 data[0x20]; ///< Empty (Profile = None) + BtmHidDeviceInfo hid; ///< \ref BtmHidDeviceInfo (Profile = Hid) + BtmAudioDeviceInfo audio; ///< \ref BtmAudioDeviceInfo (Profile = Audio) + } profile_info; + char name[0x15]; ///< Name + u8 pad[2]; ///< Padding +} BtmShortenedDeviceInfo; + /// DeviceInfoList typedef struct { u8 device_count; ///< DeviceCount diff --git a/nx/source/services/btm.c b/nx/source/services/btm.c index 8e656fef08..40f785311e 100644 --- a/nx/source/services/btm.c +++ b/nx/source/services/btm.c @@ -640,3 +640,16 @@ Result btmSetAppletResourceUserId(u64 AppletResourceUserId) { return _btmCmdInU64NoOut(AppletResourceUserId, cmd_id); } +Result btmGetShortenedDeviceInfo(BtmProfile profile, BtmShortenedDeviceInfo *out, size_t count, s32 *total_out) { + if (hosversionBefore(13,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmShortenedDeviceInfo)*count, total_out, 110); +} + +Result btmGetShortenedDeviceCondition(BtmProfile profile, BtmShortenedDeviceCondition *out, size_t count, s32 *total_out) { + if (hosversionBefore(14,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _btmCmdInIdOutBufPtr(profile, out, sizeof(BtmShortenedDeviceCondition)*count, total_out, 115); +}