From 3b670bc6526d82c8fd8ca5b270d8c44faa60fba7 Mon Sep 17 00:00:00 2001
From: yellows8 <yellows8@users.noreply.github.com>
Date: Wed, 12 Aug 2020 10:33:58 -0400
Subject: [PATCH] btdrv: Added the remaining cmds, various fixes, and added a
 types .h.

---
 nx/include/switch/services/btdrv.h       | 505 ++++++++++++++++-------
 nx/include/switch/services/btdrv_types.h | 158 +++++++
 nx/include/switch/services/btm.h         |   2 +-
 nx/include/switch/services/btmu.h        |   2 +-
 nx/source/services/btdrv.c               | 430 +++++++++++++++++--
 5 files changed, 906 insertions(+), 191 deletions(-)
 create mode 100644 nx/include/switch/services/btdrv_types.h

diff --git a/nx/include/switch/services/btdrv.h b/nx/include/switch/services/btdrv.h
index 3bf41168..58fb8f98 100644
--- a/nx/include/switch/services/btdrv.h
+++ b/nx/include/switch/services/btdrv.h
@@ -7,73 +7,10 @@
 #pragma once
 #include "../types.h"
 #include "../kernel/event.h"
+#include "../services/btdrv_types.h"
+#include "../services/set.h"
 #include "../sf/service.h"
 
-/// BluetoothPropertyType
-typedef enum {
-    BtdrvBluetoothPropertyType_Name         =    1,    ///< Name. String, max length 0xF8 excluding NUL-terminator.
-    BtdrvBluetoothPropertyType_Address      =    2,    ///< \ref BtdrvAddress
-    BtdrvBluetoothPropertyType_Unknown3     =    3,    ///< Only available with \ref btdrvSetAdapterProperty. Unknown. 3-bytes.
-    BtdrvBluetoothPropertyType_Unknown5     =    5,    ///< Unknown. 3-bytes.
-    BtdrvBluetoothPropertyType_Unknown6     =    6,    ///< Unknown. 1-byte. The default is value 0x68.
-} BtdrvBluetoothPropertyType;
-
-/// BluetoothHhReportType
-/// Bit0-1 directly control the HID bluetooth transaction report-type value.
-/// Bit2-3: these directly control the Parameter Reserved field for SetReport, for GetReport these control the Parameter Reserved and Size bits.
-typedef enum {
-    BtdrvBluetoothHhReportType_Other        =    0,    ///< Other
-    BtdrvBluetoothHhReportType_Input        =    1,    ///< Input
-    BtdrvBluetoothHhReportType_Output       =    2,    ///< Output
-    BtdrvBluetoothHhReportType_Feature      =    3,    ///< Feature
-} BtdrvBluetoothHhReportType;
-
-/// HidEventType
-typedef enum {
-    BtdrvHidEventType_Unknown0              =    0,    ///< Unknown. Only used with \ref btdrvGetHidEventInfo.
-    BtdrvHidEventType_Unknown4              =    4,    ///< Unknown.
-    BtdrvHidEventType_Unknown7              =    7,    ///< Unknown. Only used with \ref btdrvGetHidEventInfo.
-    BtdrvHidEventType_Unknown8              =    8,    ///< Unknown.
-    BtdrvHidEventType_Unknown9              =    9,    ///< Unknown.
-} BtdrvHidEventType;
-
-/// This determines the u16 data to write into the CircularBuffer (name "BLE CORE").
-typedef enum {
-    BtdrvFatalReason_Unknown1               =    1,    ///< u16 data = 0x850.
-    BtdrvFatalReason_Unknown2               =    2,    ///< u16 data = 0x851.
-    BtdrvFatalReason_Unknown3               =    3,    ///< Reason values which aren't 1/2: u16 data = 0x852.
-} BtdrvFatalReason;
-
-/// Address
-typedef struct {
-    u8 address[0x6];           ///< Address
-} BtdrvAddress;
-
-/// AdapterProperty
-typedef struct {
-    BtdrvAddress addr;         ///< Same as the data for ::BtdrvBluetoothPropertyType_Address.
-    u8 type5[0x3];             ///< Same as the data for ::BtdrvBluetoothPropertyType_Unknown5.
-    char name[0xF9];           ///< Same as the data for ::BtdrvBluetoothPropertyType_Name (last byte is not initialized).
-    u8 type6;                  ///< Set to hard-coded value 0x68 (same as the data for ::BtdrvBluetoothPropertyType_Unknown6).
-} BtdrvAdapterProperty;
-
-/// BluetoothPinCode
-typedef struct {
-    char code[0x10];           ///< PinCode
-} BtdrvBluetoothPinCode;
-
-/// HidData, for pre-9.0.0.
-typedef struct {
-    u16 size;                  ///< Size of data.
-    u8 data[0x280];            ///< Data
-} BtdrvHidData;
-
-/// HidReport, for [9.0.0+].
-typedef struct {
-    u16 size;                  ///< Size of data.
-    u8 data[0x2BC];            ///< Data
-} BtdrvHidReport;
-
 /// Data for \ref btdrvGetHidReportEventInfo. The data stored here depends on the \ref BtdrvHidEventType.
 typedef struct {
     union {
@@ -174,90 +111,6 @@ typedef struct {
     } data;
 } BtdrvHidReportEventInfoBufferData;
 
-/// PlrStatistics
-typedef struct {
-    u8 unk_x0[0x84];           ///< Unknown
-} BtdrvPlrStatistics;
-
-/// PlrList
-typedef struct {
-    u8 unk_x0[0xA4];           ///< Unknown
-} BtdrvPlrList;
-
-/// ChannelMapList
-typedef struct {
-    u8 unk_x0[0x88];           ///< Unknown
-} BtdrvChannelMapList;
-
-/// LeConnectionParams
-typedef struct {
-    u8 unk_x0[0x14];           ///< Unknown
-} BtdrvLeConnectionParams;
-
-/// BleConnectionParameter
-typedef struct {
-    u8 unk_x0[0xC];           ///< Unknown
-} BtdrvBleConnectionParameter;
-
-/// BtdrvBleAdvertisePacketDataEntry
-typedef struct {
-    u16 unk_x0;                                      ///< Unknown
-    u8 unused[0x12];                                 ///< Unused
-} BtdrvBleAdvertisePacketDataEntry;
-
-/// BleAdvertisePacketData
-typedef struct {
-    u32 unk_x0;                                      ///< Unknown
-    u8 unk_x4;                                       ///< Unknown
-    u8 size0;                                        ///< Size of the data at unk_x6.
-    u8 unk_x6[0x1F];                                 ///< Unknown, see size0.
-    u8 pad[3];                                       ///< Padding
-    u8 count;                                        ///< Total array entries, see entries.
-    u8 pad2[7];                                      ///< Padding
-    BtdrvBleAdvertisePacketDataEntry entries[0x5];   ///< \ref BtdrvBleAdvertisePacketDataEntry
-    u8 pad3[0x10];                                   ///< Padding
-    u8 size2;                                        ///< Size of the data at unk_xA8.
-    u8 unk_xA5;                                      ///< Unknown
-    u8 pad4[2];                                      ///< Padding
-    u8 unk_xA8[0x1F];                                ///< Unknown, see size2.
-    u8 unk_xC7;                                      ///< Unknown
-    u8 unk_xC8;                                      ///< Unknown
-    u8 pad5[3];                                      ///< Padding
-} BtdrvBleAdvertisePacketData;
-
-/// BleAdvertiseFilter
-typedef struct {
-    u8 unk_x0[0x3E];           ///< Unknown
-} BtdrvBleAdvertiseFilter;
-
-/// BleAdvertisePacketParameter
-typedef struct {
-    u8 data[0x8];              ///< Unknown
-} BtdrvBleAdvertisePacketParameter;
-
-/// BleScanResult
-typedef struct {
-    u8 unk_x0[0x148];          ///< Unknown
-} BtdrvBleScanResult;
-
-/// BleConnectionInfo
-typedef struct {
-    u32 id;                    ///< Id, 0xFFFFFFFF ([5.0.0-5.0.2] 0xFFFF) is invalid.
-    BtdrvAddress addr;         ///< \ref BtdrvAddress
-    u8 pad[2];                 ///< Padding
-} BtdrvBleConnectionInfo;
-
-/// GattAttributeUuid
-typedef struct {
-    u32 size;                  ///< UUID size, must be 0x2, 0x4, or 0x10.
-    u8 uuid[0x10];             ///< UUID with the above size.
-} BtdrvGattAttributeUuid;
-
-/// GattId
-typedef struct {
-    u8 unk_x0[0x18];           ///< Unknown
-} BtdrvGattId;
-
 /// CircularBuffer
 typedef struct {
     Mutex mutex;
@@ -279,6 +132,32 @@ void btdrvExit(void);
 /// Gets the Service object for the actual btdrv service session.
 Service* btdrvGetServiceSession(void);
 
+/**
+ * @brief InitializeBluetooth
+ * @note This is used by btm-sysmodule, this should not be used by other processes.
+ * @note The Event must be closed by the user once finished with it.
+ * @param[out] out_event Output Event with autoclear=true.
+ */
+Result btdrvInitializeBluetooth(Event* out_event);
+
+/**
+ * @brief EnableBluetooth
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvEnableBluetooth(void);
+
+/**
+ * @brief DisableBluetooth
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvDisableBluetooth(void);
+
+/**
+ * @brief FinalizeBluetooth
+ * @note This is not used by btm-sysmodule, this should not be used by other processes.
+ */
+Result btdrvFinalizeBluetooth(void);
+
 /**
  * @brief GetAdapterProperties
  * @param[out] property \ref BtdrvAdapterProperty
@@ -301,6 +180,59 @@ Result btdrvGetAdapterProperty(BtdrvBluetoothPropertyType type, void* buffer, si
  */
 Result btdrvSetAdapterProperty(BtdrvBluetoothPropertyType type, const void* buffer, size_t size);
 
+/**
+ * @brief StartInquiry
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvStartInquiry(void);
+
+/**
+ * @brief StopInquiry
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvStopInquiry(void);
+
+/**
+ * @brief CreateBond
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] type TransportType
+ */
+Result btdrvCreateBond(BtdrvAddress addr, u32 type);
+
+/**
+ * @brief RemoveBond
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ */
+Result btdrvRemoveBond(BtdrvAddress addr);
+
+/**
+ * @brief CancelBond
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ */
+Result btdrvCancelBond(BtdrvAddress addr);
+
+/**
+ * @brief RespondToPinRequest
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] flag Flag
+ * @param[in] pin_code \ref BtdrvBluetoothPinCode
+ * @param[in] unk Unknown
+ */
+Result btdrvRespondToPinRequest(BtdrvAddress addr, bool flag, const BtdrvBluetoothPinCode *pin_code, u8 unk);
+
+/**
+ * @brief RespondToSspRequest
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] variant BluetoothSspVariant
+ * @param[in] flag Flag
+ * @param[in] unk Unknown
+ */
+Result btdrvRespondToSspRequest(BtdrvAddress addr, u8 variant, bool flag, u32 unk);
+
 /**
  * @brief GetEventInfo
  * @note This is used by btm-sysmodule.
@@ -310,6 +242,28 @@ Result btdrvSetAdapterProperty(BtdrvBluetoothPropertyType type, const void* buff
  */
 Result btdrvGetEventInfo(void* buffer, size_t size, u32 *type);
 
+/**
+ * @brief InitializeHid
+ * @note This is used by btm-sysmodule, this should not be used by other processes.
+ * @note The Event must be closed by the user once finished with it.
+ * @param[out] out_event Output Event with autoclear=true.
+ */
+Result btdrvInitializeHid(Event* out_event);
+
+/**
+ * @brief OpenHidConnection
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ */
+Result btdrvOpenHidConnection(BtdrvAddress addr);
+
+/**
+ * @brief CloseHidConnection
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ */
+Result btdrvCloseHidConnection(BtdrvAddress addr);
+
 /**
  * @brief This sends a HID DATA transaction packet with report-type Output.
  * @param[in] addr \ref BtdrvAddress
@@ -349,6 +303,27 @@ Result btdrvGetHidReport(BtdrvAddress addr, u8 report_id, BtdrvBluetoothHhReport
  */
 Result btdrvTriggerConnection(BtdrvAddress addr, u16 unk);
 
+/**
+ * @brief AddPairedDeviceInfo
+ * @note This is used by btm-sysmodule.
+ * @param[in] settings \ref SetSysBluetoothDevicesSettings
+ */
+Result btdrvAddPairedDeviceInfo(const SetSysBluetoothDevicesSettings *settings);
+
+/**
+ * @brief GetPairedDeviceInfo
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[out] settings \ref SetSysBluetoothDevicesSettings
+ */
+Result btdrvGetPairedDeviceInfo(BtdrvAddress addr, SetSysBluetoothDevicesSettings *settings);
+
+/**
+ * @brief FinalizeHid
+ * @note This is not used by btm-sysmodule, this should not be used by other processes.
+ */
+Result btdrvFinalizeHid(void);
+
 /**
  * @brief GetHidEventInfo
  * @note This is used by btm-sysmodule.
@@ -358,6 +333,73 @@ Result btdrvTriggerConnection(BtdrvAddress addr, u16 unk);
  */
 Result btdrvGetHidEventInfo(void* buffer, size_t size, BtdrvHidEventType *type);
 
+/**
+ * @brief SetTsi
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] unk Unknown
+ */
+Result btdrvSetTsi(BtdrvAddress addr, u8 unk);
+
+/**
+ * @brief EnableBurstMode
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] flag Flag
+ */
+Result btdrvEnableBurstMode(BtdrvAddress addr, bool flag);
+
+/**
+ * @brief SetZeroRetransmission
+ * @note This is used by btm-sysmodule.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] buf Input buffer containing an array of u8s.
+ * @param[in] count Total u8s in the input buffer. This can be 0, the max is 5.
+ */
+Result btdrvSetZeroRetransmission(BtdrvAddress addr, u8 *buf, u8 count);
+
+/**
+ * @brief EnableMcMode
+ * @note This is used by btm-sysmodule.
+ * @param[in] flag Flag
+ */
+Result btdrvEnableMcMode(bool flag);
+
+/**
+ * @brief EnableLlrScan
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvEnableLlrScan(void);
+
+/**
+ * @brief DisableLlrScan
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvDisableLlrScan(void);
+
+/**
+ * @brief EnableRadio
+ * @note This is used by btm-sysmodule.
+ * @param[in] flag Flag
+ */
+Result btdrvEnableRadio(bool flag);
+
+/**
+ * @brief SetVisibility
+ * @note This is used by btm-sysmodule.
+ * @param[in] flag0 Unknown flag.
+ * @param[in] flag1 Unknown flag.
+ */
+Result btdrvSetVisibility(bool flag0, bool flag1);
+
+/**
+ * @brief EnableTbfcScan
+ * @note Only available on [4.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] flag Flag
+ */
+Result btdrvEnableTbfcScan(bool flag);
+
 /**
  * @brief RegisterHidReportEvent
  * @note This also does sharedmem init/handling if needed, on [7.0.0+].
@@ -386,6 +428,13 @@ void* btdrvGetHidReportEventInfoSharedmemAddr(void);
  */
 Result btdrvGetLatestPlr(BtdrvPlrList *out);
 
+/**
+ * @brief GetPendingConnections
+ * @note This is used by btm-sysmodule.
+ * @note Only available on [3.0.0+].
+ */
+Result btdrvGetPendingConnections(void);
+
 /**
  * @brief GetChannelMap
  * @note Only available on [3.0.0+].
@@ -421,6 +470,35 @@ Result btdrvEnableAfhSetting(bool flag);
  */
 Result btdrvIsAfhSettingEnabled(bool *out);
 
+/**
+ * @brief InitializeBle
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @note The Event must be closed by the user once finished with it.
+ * @param[out] out_event Output Event with autoclear=true.
+ */
+Result btdrvInitializeBle(Event* out_event);
+
+/**
+ * @brief EnableBle
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvEnableBle(void);
+
+/**
+ * @brief DisableBle
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvDisableBle(void);
+
+/**
+ * @brief FinalizeBle
+ * @note Only available on [5.0.0+].
+ */
+Result btdrvFinalizeBle(void);
+
 /**
  * @brief SetBleVisibility
  * @note Only available on [5.0.0+].
@@ -429,6 +507,36 @@ Result btdrvIsAfhSettingEnabled(bool *out);
  */
 Result btdrvSetBleVisibility(bool flag0, bool flag1);
 
+/**
+ * @brief SetLeConnectionParameter
+ * @note Only available on [5.0.0-8.1.1]. This is the older version of \ref btdrvSetBleConnectionParameter.
+ * @param[in] param \ref BtdrvLeConnectionParams
+ */
+Result btdrvSetLeConnectionParameter(const BtdrvLeConnectionParams *param);
+
+/**
+ * @brief SetBleConnectionParameter
+ * @note Only available on [9.0.0+]. This is the newer version of \ref btdrvSetLeConnectionParameter.
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] param \ref BtdrvBleConnectionParameter
+ * @param[in] flag Flag
+ */
+Result btdrvSetBleConnectionParameter(BtdrvAddress addr, const BtdrvBleConnectionParameter *param, bool flag);
+
+/**
+ * @brief SetLeDefaultConnectionParameter
+ * @note Only available on [5.0.0-8.1.1]. This is the older version of \ref btdrvSetBleDefaultConnectionParameter.
+ * @param[in] param \ref BtdrvLeConnectionParams
+ */
+Result btdrvSetLeDefaultConnectionParameter(const BtdrvLeConnectionParams *param);
+
+/**
+ * @brief SetBleDefaultConnectionParameter
+ * @note Only available on [9.0.0+]. This is the newer version of \ref btdrvSetLeDefaultConnectionParameter.
+ * @param[in] param \ref BtdrvBleConnectionParameter
+ */
+Result btdrvSetBleDefaultConnectionParameter(const BtdrvBleConnectionParameter *param);
+
 /**
  * @brief SetBleAdvertiseData
  * @note Only available on [5.0.0+].
@@ -445,6 +553,58 @@ Result btdrvSetBleAdvertiseData(const BtdrvBleAdvertisePacketData *data);
  */
 Result btdrvSetBleAdvertiseParameter(BtdrvAddress addr, u16 unk0, u16 unk1);
 
+/**
+ * @brief StartBleScan
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvStartBleScan(void);
+
+/**
+ * @brief StopBleScan
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvStopBleScan(void);
+
+/**
+ * @brief AddBleScanFilterCondition
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] filter \ref BtdrvBleAdvertiseFilter
+ */
+Result btdrvAddBleScanFilterCondition(const BtdrvBleAdvertiseFilter *filter);
+
+/**
+ * @brief DeleteBleScanFilterCondition
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] filter \ref BtdrvBleAdvertiseFilter
+ */
+Result btdrvDeleteBleScanFilterCondition(const BtdrvBleAdvertiseFilter *filter);
+
+/**
+ * @brief DeleteBleScanFilter
+ * @note Only available on [5.0.0+].
+ * @param[in] unk Unknown
+ */
+Result btdrvDeleteBleScanFilter(u8 unk);
+
+/**
+ * @brief ClearBleScanFilters
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ */
+Result btdrvClearBleScanFilters(void);
+
+/**
+ * @brief EnableBleScanFilter
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] flag Flag
+ */
+Result btdrvEnableBleScanFilter(bool flag);
+
 /**
  * @brief RegisterGattClient
  * @note Only available on [5.0.0+].
@@ -466,6 +626,35 @@ Result btdrvUnregisterGattClient(u8 unk);
  */
 Result btdrvUnregisterAllGattClients(void);
 
+/**
+ * @brief ConnectGattServer
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] unk Unknown
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] flag Flag
+ * @param[in] AppletResourceUserId AppletResourceUserId
+ */
+Result btdrvConnectGattServer(u8 unk, BtdrvAddress addr, bool flag, u64 AppletResourceUserId);
+
+/**
+ * @brief CancelConnectGattServer
+ * @note Only available on [5.1.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] unk Unknown
+ * @param[in] addr \ref BtdrvAddress
+ * @param[in] flag Flag
+ */
+Result btdrvCancelConnectGattServer(u8 unk, BtdrvAddress addr, bool flag);
+
+/**
+ * @brief DisconnectGattServer
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] unk Unknown
+ */
+Result btdrvDisconnectGattServer(u32 unk);
+
 /**
  * @brief GetGattAttribute
  * @note Only available on [5.0.0+].
@@ -482,6 +671,15 @@ Result btdrvGetGattAttribute(BtdrvAddress addr, u32 unk);
  */
 Result btdrvGetGattService(u32 unk, const BtdrvGattAttributeUuid *uuid);
 
+/**
+ * @brief ConfigureAttMtu
+ * @note Only available on [5.0.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] unk Unknown
+ * @param[in] mtu MTU
+ */
+Result btdrvConfigureAttMtu(u32 unk, u16 mtu);
+
 /**
  * @brief RegisterGattServer
  * @note Only available on [5.0.0+].
@@ -748,6 +946,15 @@ Result btdrvGetLeHidEventInfo(void* buffer, size_t size, u32 *type);
  */
 Result btdrvRegisterBleHidEvent(Event* out_event);
 
+/**
+ * @brief SetBleScanParameter
+ * @note Only available on [5.1.0+].
+ * @note This is used by btm-sysmodule.
+ * @param[in] unk0 Unknown
+ * @param[in] unk1 Unknown
+ */
+Result btdrvSetBleScanParameter(u16 unk0, u16 unk1);
+
 /**
  * @brief MoveToSecondaryPiconet
  * @note Only available on [10.0.0+].
diff --git a/nx/include/switch/services/btdrv_types.h b/nx/include/switch/services/btdrv_types.h
new file mode 100644
index 00000000..82b09a64
--- /dev/null
+++ b/nx/include/switch/services/btdrv_types.h
@@ -0,0 +1,158 @@
+/**
+ * @file btdrv_types.h
+ * @brief Bluetooth driver (btdrv) service types (see btdrv.h for the rest).
+ * @author yellows8
+ * @copyright libnx Authors
+ */
+#pragma once
+#include "../types.h"
+
+/// BluetoothPropertyType
+typedef enum {
+    BtdrvBluetoothPropertyType_Name         =    1,    ///< Name. String, max length 0xF8 excluding NUL-terminator.
+    BtdrvBluetoothPropertyType_Address      =    2,    ///< \ref BtdrvAddress
+    BtdrvBluetoothPropertyType_Unknown3     =    3,    ///< Only available with \ref btdrvSetAdapterProperty. Unknown. 3-bytes.
+    BtdrvBluetoothPropertyType_Unknown5     =    5,    ///< Unknown. 3-bytes.
+    BtdrvBluetoothPropertyType_Unknown6     =    6,    ///< Unknown. 1-byte. The default is value 0x68.
+} BtdrvBluetoothPropertyType;
+
+/// BluetoothHhReportType
+/// Bit0-1 directly control the HID bluetooth transaction report-type value.
+/// Bit2-3: these directly control the Parameter Reserved field for SetReport, for GetReport these control the Parameter Reserved and Size bits.
+typedef enum {
+    BtdrvBluetoothHhReportType_Other        =    0,    ///< Other
+    BtdrvBluetoothHhReportType_Input        =    1,    ///< Input
+    BtdrvBluetoothHhReportType_Output       =    2,    ///< Output
+    BtdrvBluetoothHhReportType_Feature      =    3,    ///< Feature
+} BtdrvBluetoothHhReportType;
+
+/// HidEventType
+typedef enum {
+    BtdrvHidEventType_Unknown0              =    0,    ///< Unknown. Only used with \ref btdrvGetHidEventInfo.
+    BtdrvHidEventType_Unknown4              =    4,    ///< Unknown.
+    BtdrvHidEventType_Unknown7              =    7,    ///< Unknown. Only used with \ref btdrvGetHidEventInfo.
+    BtdrvHidEventType_Unknown8              =    8,    ///< Unknown.
+    BtdrvHidEventType_Unknown9              =    9,    ///< Unknown.
+} BtdrvHidEventType;
+
+/// This determines the u16 data to write into the CircularBuffer (name "BLE CORE").
+typedef enum {
+    BtdrvFatalReason_Unknown1               =    1,    ///< u16 data = 0x850.
+    BtdrvFatalReason_Unknown2               =    2,    ///< u16 data = 0x851.
+    BtdrvFatalReason_Unknown3               =    3,    ///< Reason values which aren't 1/2: u16 data = 0x852.
+} BtdrvFatalReason;
+
+/// Address
+typedef struct {
+    u8 address[0x6];           ///< Address
+} BtdrvAddress;
+
+/// AdapterProperty
+typedef struct {
+    BtdrvAddress addr;         ///< Same as the data for ::BtdrvBluetoothPropertyType_Address.
+    u8 type5[0x3];             ///< Same as the data for ::BtdrvBluetoothPropertyType_Unknown5.
+    char name[0xF9];           ///< Same as the data for ::BtdrvBluetoothPropertyType_Name (last byte is not initialized).
+    u8 type6;                  ///< Set to hard-coded value 0x68 (same as the data for ::BtdrvBluetoothPropertyType_Unknown6).
+} BtdrvAdapterProperty;
+
+/// BluetoothPinCode
+typedef struct {
+    char code[0x10];           ///< PinCode
+} BtdrvBluetoothPinCode;
+
+/// HidData, for pre-9.0.0.
+typedef struct {
+    u16 size;                  ///< Size of data.
+    u8 data[0x280];            ///< Data
+} BtdrvHidData;
+
+/// HidReport, for [9.0.0+].
+typedef struct {
+    u16 size;                  ///< Size of data.
+    u8 data[0x2BC];            ///< Data
+} BtdrvHidReport;
+
+/// PlrStatistics
+typedef struct {
+    u8 unk_x0[0x84];           ///< Unknown
+} BtdrvPlrStatistics;
+
+/// PlrList
+typedef struct {
+    u8 unk_x0[0xA4];           ///< Unknown
+} BtdrvPlrList;
+
+/// ChannelMapList
+typedef struct {
+    u8 unk_x0[0x88];           ///< Unknown
+} BtdrvChannelMapList;
+
+/// LeConnectionParams
+typedef struct {
+    u8 unk_x0[0x14];           ///< Unknown
+} BtdrvLeConnectionParams;
+
+/// BleConnectionParameter
+typedef struct {
+    u8 unk_x0[0xC];           ///< Unknown
+} BtdrvBleConnectionParameter;
+
+/// BtdrvBleAdvertisePacketDataEntry
+typedef struct {
+    u16 unk_x0;                                      ///< Unknown
+    u8 unused[0x12];                                 ///< Unused
+} BtdrvBleAdvertisePacketDataEntry;
+
+/// BleAdvertisePacketData
+typedef struct {
+    u32 unk_x0;                                      ///< Unknown
+    u8 unk_x4;                                       ///< Unknown
+    u8 size0;                                        ///< Size of the data at unk_x6.
+    u8 unk_x6[0x1F];                                 ///< Unknown, see size0.
+    u8 pad[3];                                       ///< Padding
+    u8 count;                                        ///< Total array entries, see entries.
+    u8 pad2[7];                                      ///< Padding
+    BtdrvBleAdvertisePacketDataEntry entries[0x5];   ///< \ref BtdrvBleAdvertisePacketDataEntry
+    u8 pad3[0x10];                                   ///< Padding
+    u8 size2;                                        ///< Size of the data at unk_xA8.
+    u8 unk_xA5;                                      ///< Unknown
+    u8 pad4[2];                                      ///< Padding
+    u8 unk_xA8[0x1F];                                ///< Unknown, see size2.
+    u8 unk_xC7;                                      ///< Unknown
+    u8 unk_xC8;                                      ///< Unknown
+    u8 pad5[3];                                      ///< Padding
+} BtdrvBleAdvertisePacketData;
+
+/// BleAdvertiseFilter
+typedef struct {
+    u8 unk_x0[0x3E];           ///< Unknown
+} BtdrvBleAdvertiseFilter;
+
+/// BleAdvertisePacketParameter
+typedef struct {
+    u8 data[0x8];              ///< Unknown
+} BtdrvBleAdvertisePacketParameter;
+
+/// BleScanResult
+typedef struct {
+    u8 unk_x0[0x148];          ///< Unknown
+} BtdrvBleScanResult;
+
+/// BleConnectionInfo
+typedef struct {
+    u32 id;                    ///< Id, 0xFFFFFFFF ([5.0.0-5.0.2] 0xFFFF) is invalid.
+    BtdrvAddress addr;         ///< \ref BtdrvAddress
+    u8 pad[2];                 ///< Padding
+} BtdrvBleConnectionInfo;
+
+/// GattAttributeUuid
+typedef struct {
+    u32 size;                  ///< UUID size, must be 0x2, 0x4, or 0x10.
+    u8 uuid[0x10];             ///< UUID with the above size.
+} BtdrvGattAttributeUuid;
+
+/// GattId
+typedef struct {
+    u8 unk_x0[0x18];           ///< Unknown
+} BtdrvGattId;
+
diff --git a/nx/include/switch/services/btm.h b/nx/include/switch/services/btm.h
index f8fc4757..848c779d 100644
--- a/nx/include/switch/services/btm.h
+++ b/nx/include/switch/services/btm.h
@@ -6,7 +6,7 @@
 #pragma once
 #include "../types.h"
 #include "../kernel/event.h"
-#include "../services/btdrv.h"
+#include "../services/btdrv_types.h"
 #include "../sf/service.h"
 
 /// HostDeviceProperty
diff --git a/nx/include/switch/services/btmu.h b/nx/include/switch/services/btmu.h
index 5b5321c3..36594058 100644
--- a/nx/include/switch/services/btmu.h
+++ b/nx/include/switch/services/btmu.h
@@ -7,7 +7,7 @@
 #pragma once
 #include "../types.h"
 #include "../kernel/event.h"
-#include "../services/btdrv.h"
+#include "../services/btdrv_types.h"
 #include "../services/btm.h"
 #include "../sf/service.h"
 
diff --git a/nx/source/services/btdrv.c b/nx/source/services/btdrv.c
index 3a31e060..525c3001 100644
--- a/nx/source/services/btdrv.c
+++ b/nx/source/services/btdrv.c
@@ -54,6 +54,15 @@ static Result _btdrvCmdInBoolNoOut(bool inval, u32 cmd_id) {
     return _btdrvCmdInU8NoOut(inval!=0, cmd_id);
 }
 
+static Result _btdrvCmdTwoInBoolsNoOut(bool flag0, bool flag1, u32 cmd_id) {
+    const struct {
+        u8 flag;
+        u8 flag2;
+    } in = { flag0!=0, flag1!=0 };
+
+    return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
+}
+
 static Result _btdrvCmdInU32NoOut(u32 inval, u32 cmd_id) {
     return serviceDispatchIn(&g_btdrvSrv, cmd_id, inval);
 }
@@ -62,6 +71,19 @@ static Result _btdrvCmdInAddrNoOut(BtdrvAddress addr, u32 cmd_id) {
     return serviceDispatchIn(&g_btdrvSrv, cmd_id, addr);
 }
 
+static Result _btmCmdInAddrU8NoOut(BtdrvAddress addr, u8 inval, u32 cmd_id) {
+    const struct {
+        BtdrvAddress addr;
+        u8 inval;
+    } in = { addr, inval };
+
+    return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
+}
+
+static Result _btdrvCmdInLeConnectionParameterNoOut(const BtdrvLeConnectionParams *param, u32 cmd_id) {
+    return serviceDispatchIn(&g_btdrvSrv, cmd_id, *param);
+}
+
 static Result _btdrvCmdInUuidNoOut(const BtdrvGattAttributeUuid *uuid, u32 cmd_id) {
     return serviceDispatchIn(&g_btdrvSrv, cmd_id, *uuid);
 }
@@ -107,6 +129,34 @@ static Result _btdrvCmdOutU32OutBuf(void* buffer, size_t size, u32 *out, u32 cmd
     );
 }
 
+static Result _btdrvGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1, u32 cmd_id) {
+    const struct {
+        u8 flag;
+        u8 pad[3];
+        u32 unk;
+        BtdrvGattId id0;
+        BtdrvGattId id1;
+    } in = { flag!=0, {0}, unk, *id0, *id1 };
+
+    return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
+}
+
+Result btdrvInitializeBluetooth(Event* out_event) {
+    return _btdrvCmdGetEvent(out_event, true, 1);
+}
+
+Result btdrvEnableBluetooth(void) {
+    return _btdrvCmdNoIO(2);
+}
+
+Result btdrvDisableBluetooth(void) {
+    return _btdrvCmdNoIO(3);
+}
+
+Result btdrvFinalizeBluetooth(void) {
+    return _btdrvCmdNoIO(4);
+}
+
 Result btdrvGetAdapterProperties(BtdrvAdapterProperty *property) {
     return serviceDispatch(&g_btdrvSrv, 5,
         .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out | SfBufferAttr_FixedSize },
@@ -130,10 +180,88 @@ Result btdrvSetAdapterProperty(BtdrvBluetoothPropertyType type, const void* buff
     );
 }
 
+Result btdrvStartInquiry(void) {
+    return _btdrvCmdNoIO(8);
+}
+
+Result btdrvStopInquiry(void) {
+    return _btdrvCmdNoIO(9);
+}
+
+Result btdrvCreateBond(BtdrvAddress addr, u32 type) {
+    if (hosversionBefore(9,0,0)) {
+        return serviceDispatchIn(&g_btdrvSrv, 10, addr,
+            .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In | SfBufferAttr_FixedSize },
+            .buffers = { { &type, sizeof(type) } },
+        );
+    }
+
+    const struct {
+        BtdrvAddress addr;
+        u8 pad[2];
+        u32 type;
+    } in = { addr, {0}, type };
+
+    return serviceDispatchIn(&g_btdrvSrv, 10, in);
+}
+
+Result btdrvRemoveBond(BtdrvAddress addr) {
+    return _btdrvCmdInAddrNoOut(addr, 11);
+}
+
+Result btdrvCancelBond(BtdrvAddress addr) {
+    return _btdrvCmdInAddrNoOut(addr, 12);
+}
+
+Result btdrvRespondToPinRequest(BtdrvAddress addr, bool flag, const BtdrvBluetoothPinCode *pin_code, u8 unk) {
+    const struct {
+        BtdrvAddress addr;
+        u8 flag;
+        u8 unk;
+        BtdrvBluetoothPinCode pin_code;
+    } in = { addr, flag!=0, unk, *pin_code };
+
+    return serviceDispatchIn(&g_btdrvSrv, 13, in);
+}
+
+Result btdrvRespondToSspRequest(BtdrvAddress addr, u8 variant, bool flag, u32 unk) {
+    const struct {
+        BtdrvAddress addr;
+        u8 variant;
+        u8 flag;
+        u32 unk;
+    } in = { addr, variant, flag!=0, unk };
+
+    return serviceDispatchIn(&g_btdrvSrv, 14, in);
+}
+
 Result btdrvGetEventInfo(void* buffer, size_t size, u32 *type) {
     return _btdrvCmdOutU32OutBuf(buffer, size, type, 15);
 }
 
+Result btdrvInitializeHid(Event* out_event) {
+    Handle tmp_handle = INVALID_HANDLE;
+    Result rc = 0;
+    u16 tmp=0x1;
+
+    if (R_SUCCEEDED(rc)) {
+        rc = serviceDispatchIn(&g_btdrvSrv, 16, tmp,
+            .out_handle_attrs = { SfOutHandleAttr_HipcCopy },
+            .out_handles = &tmp_handle,
+        );
+    }
+    if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, true);
+    return rc;
+}
+
+Result btdrvOpenHidConnection(BtdrvAddress addr) {
+    return _btdrvCmdInAddrNoOut(addr, 17);
+}
+
+Result btdrvCloseHidConnection(BtdrvAddress addr) {
+    return _btdrvCmdInAddrNoOut(addr, 18);
+}
+
 Result btdrvWriteHidData(BtdrvAddress addr, BtdrvHidReport *buffer) {
     size_t size = hosversionBefore(9,0,0) ? sizeof(BtdrvHidData) : sizeof(BtdrvHidReport);
     return serviceDispatchIn(&g_btdrvSrv, 19, addr,
@@ -154,8 +282,9 @@ Result btdrvSetHidReport(BtdrvAddress addr, BtdrvBluetoothHhReportType type, Btd
 
     const struct {
         BtdrvAddress addr;
+        u8 pad[2];
         u32 type;
-    } in = { addr, type };
+    } in = { addr, {0}, type };
 
     return serviceDispatchIn(&g_btdrvSrv, 21, in,
         .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In | SfBufferAttr_FixedSize },
@@ -185,6 +314,21 @@ Result btdrvTriggerConnection(BtdrvAddress addr, u16 unk) {
     return serviceDispatchIn(&g_btdrvSrv, 23, in);
 }
 
+Result btdrvAddPairedDeviceInfo(const SetSysBluetoothDevicesSettings *settings) {
+    return _btdrvCmdInBufPtrFixed(settings, sizeof(*settings), 24);
+}
+
+Result btdrvGetPairedDeviceInfo(BtdrvAddress addr, SetSysBluetoothDevicesSettings *settings) {
+    return serviceDispatchIn(&g_btdrvSrv, 25, addr,
+        .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out | SfBufferAttr_FixedSize },
+        .buffers = { { settings, sizeof(*settings) } },
+    );
+}
+
+Result btdrvFinalizeHid(void) {
+    return _btdrvCmdNoIO(26);
+}
+
 Result btdrvGetHidEventInfo(void* buffer, size_t size, BtdrvHidEventType *type) {
     u32 tmp=0;
     Result rc = _btdrvCmdOutU32OutBuf(buffer, size, &tmp, 27);
@@ -192,6 +336,48 @@ Result btdrvGetHidEventInfo(void* buffer, size_t size, BtdrvHidEventType *type)
     return rc;
 }
 
+Result btdrvSetTsi(BtdrvAddress addr, u8 unk) {
+    return _btmCmdInAddrU8NoOut(addr, unk, 28);
+}
+
+Result btdrvEnableBurstMode(BtdrvAddress addr, bool flag) {
+    return _btmCmdInAddrU8NoOut(addr, flag!=0, 29);
+}
+
+Result btdrvSetZeroRetransmission(BtdrvAddress addr, u8 *buf, u8 count) {
+    return serviceDispatchIn(&g_btdrvSrv, 30, addr,
+        .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
+        .buffers = { { buf, count } },
+    );
+}
+
+Result btdrvEnableMcMode(bool flag) {
+    return _btdrvCmdInBoolNoOut(flag, 31);
+}
+
+Result btdrvEnableLlrScan(void) {
+    return _btdrvCmdNoIO(32);
+}
+
+Result btdrvDisableLlrScan(void) {
+    return _btdrvCmdNoIO(33);
+}
+
+Result btdrvEnableRadio(bool flag) {
+    return _btdrvCmdInBoolNoOut(flag, 34);
+}
+
+Result btdrvSetVisibility(bool flag0, bool flag1) {
+    return _btdrvCmdTwoInBoolsNoOut(flag0, flag1, 35);
+}
+
+Result btdrvEnableTbfcScan(bool flag) {
+    if (hosversionBefore(4,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInBoolNoOut(flag, 36);
+}
+
 Result btdrvRegisterHidReportEvent(Event* out_event) {
     Result rc=0;
     Handle tmphandle=0;
@@ -279,6 +465,14 @@ Result btdrvGetLatestPlr(BtdrvPlrList *out) {
     return _btdrvCmdOutBufAliasFixed(out, size, cmd_id);
 }
 
+Result btdrvGetPendingConnections(void) {
+    if (hosversionBefore(3,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+    u32 cmd_id = hosversionBefore(4,0,0) ? 39 : 40;
+
+    return _btdrvCmdNoIO(cmd_id);
+}
+
 Result btdrvGetChannelMap(BtdrvChannelMapList *out) {
     if (hosversionBefore(3,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
@@ -319,16 +513,74 @@ Result btdrvIsAfhSettingEnabled(bool *out) {
     return _btdrvCmdNoInOutBool(out, cmd_id);
 }
 
+Result btdrvInitializeBle(Event* out_event) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdGetEvent(out_event, true, 46);
+}
+
+Result btdrvEnableBle(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(47);
+}
+
+Result btdrvDisableBle(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(48);
+}
+
+Result btdrvFinalizeBle(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(49);
+}
+
 Result btdrvSetBleVisibility(bool flag0, bool flag1) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
 
-    const struct {
-        u8 flag;
-        u8 flag2;
-    } in = { flag0!=0, flag1!=0 };
+    return _btdrvCmdTwoInBoolsNoOut(flag0, flag1, 50);
+}
 
-    return serviceDispatchIn(&g_btdrvSrv, 50, in);
+Result btdrvSetLeConnectionParameter(const BtdrvLeConnectionParams *param) {
+    if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInLeConnectionParameterNoOut(param, 51);
+}
+
+Result btdrvSetBleConnectionParameter(BtdrvAddress addr, const BtdrvBleConnectionParameter *param, bool flag) {
+    if (hosversionBefore(9,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    const struct {
+        BtdrvAddress addr;
+        u8 flag;
+        u8 pad;
+        BtdrvBleConnectionParameter param;
+    } in = { addr, flag!=0, 0, *param };
+
+    return serviceDispatchIn(&g_btdrvSrv, 51, in);
+}
+
+Result btdrvSetLeDefaultConnectionParameter(const BtdrvLeConnectionParams *param) {
+    if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInLeConnectionParameterNoOut(param, 52);
+}
+
+Result btdrvSetBleDefaultConnectionParameter(const BtdrvBleConnectionParameter *param) {
+    if (hosversionBefore(9,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return serviceDispatchIn(&g_btdrvSrv, 52, *param);
 }
 
 Result btdrvSetBleAdvertiseData(const BtdrvBleAdvertisePacketData *data) {
@@ -351,6 +603,55 @@ Result btdrvSetBleAdvertiseParameter(BtdrvAddress addr, u16 unk0, u16 unk1) {
     return serviceDispatchIn(&g_btdrvSrv, 54, in);
 }
 
+Result btdrvStartBleScan(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(55);
+}
+
+Result btdrvStopBleScan(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(56);
+}
+
+Result btdrvAddBleScanFilterCondition(const BtdrvBleAdvertiseFilter *filter) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInBufPtrFixed(filter, sizeof(*filter), 57);
+}
+
+Result btdrvDeleteBleScanFilterCondition(const BtdrvBleAdvertiseFilter *filter) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInBufPtrFixed(filter, sizeof(*filter), 58);
+}
+
+Result btdrvDeleteBleScanFilter(u8 unk) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInU8NoOut(unk, 59);
+}
+
+Result btdrvClearBleScanFilters(void) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdNoIO(60);
+}
+
+Result btdrvEnableBleScanFilter(bool flag) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    return _btdrvCmdInBoolNoOut(flag, 61);
+}
+
 Result btdrvRegisterGattClient(const BtdrvGattAttributeUuid *uuid) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
@@ -372,10 +673,45 @@ Result btdrvUnregisterAllGattClients(void) {
     return _btdrvCmdNoIO(64);
 }
 
+Result btdrvConnectGattServer(u8 unk, BtdrvAddress addr, bool flag, u64 AppletResourceUserId) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    const struct {
+        u8 unk;
+        BtdrvAddress addr;
+        u8 flag;
+        u64 AppletResourceUserId;
+    } in = { unk, addr, flag!=0, AppletResourceUserId };
+
+    return serviceDispatchIn(&g_btdrvSrv, 65, in);
+}
+
+Result btdrvCancelConnectGattServer(u8 unk, BtdrvAddress addr, bool flag) {
+    if (hosversionBefore(5,1,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    const struct {
+        u8 unk;
+        BtdrvAddress addr;
+        u8 flag;
+    } in = { unk, addr, flag!=0 };
+
+    return serviceDispatchIn(&g_btdrvSrv, 66, in);
+}
+
+Result btdrvDisconnectGattServer(u32 unk) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+    u32 cmd_id = hosversionBefore(5,1,0) ? 66 : 67;
+
+    return _btdrvCmdInU32NoOut(unk, cmd_id);
+}
+
 Result btdrvGetGattAttribute(BtdrvAddress addr, u32 unk) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 67 : 68;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 67 : 68;
 
     if (hosversionBefore(9,0,0)) {
         const struct {
@@ -385,13 +721,13 @@ Result btdrvGetGattAttribute(BtdrvAddress addr, u32 unk) {
 
         return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
     }
-    return serviceDispatchIn(&g_btdrvSrv, cmd_id, unk);
+    return _btdrvCmdInU32NoOut(unk, cmd_id);
 }
 
 Result btdrvGetGattService(u32 unk, const BtdrvGattAttributeUuid *uuid) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 68 : 69;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 68 : 69;
 
     const struct {
         u32 unk0;
@@ -401,10 +737,24 @@ Result btdrvGetGattService(u32 unk, const BtdrvGattAttributeUuid *uuid) {
     return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
 }
 
+Result btdrvConfigureAttMtu(u32 unk, u16 mtu) {
+    if (hosversionBefore(5,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+    u32 cmd_id = hosversionBefore(5,1,0) ? 69 : 70;
+
+    const struct {
+        u16 mtu;
+        u16 pad;
+        u32 unk;
+    } in = { mtu, 0, unk };
+
+    return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
+}
+
 Result btdrvRegisterGattServer(const BtdrvGattAttributeUuid *uuid) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 71 : 70;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 70 : 71;
 
     return _btdrvCmdInUuidNoOut(uuid, cmd_id);
 }
@@ -412,7 +762,7 @@ Result btdrvRegisterGattServer(const BtdrvGattAttributeUuid *uuid) {
 Result btdrvUnregisterGattServer(u8 unk) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 71 : 72;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 71 : 72;
 
     return _btdrvCmdInU8NoOut(unk, cmd_id);
 }
@@ -420,7 +770,7 @@ Result btdrvUnregisterGattServer(u8 unk) {
 Result btdrvConnectGattClient(u8 unk, BtdrvAddress addr, bool flag) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 72 : 73;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 72 : 73;
 
     const struct {
         u8 unk;
@@ -434,7 +784,7 @@ Result btdrvConnectGattClient(u8 unk, BtdrvAddress addr, bool flag) {
 Result btdrvDisconnectGattClient(u8 unk, BtdrvAddress addr) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 73 : 74;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 73 : 74;
 
     if (hosversionBefore(9,0,0)) {
         const struct {
@@ -465,7 +815,7 @@ Result btdrvAddGattService(u8 unk0, u8 unk1, bool flag, const BtdrvGattAttribute
 Result btdrvEnableGattService(u8 unk, const BtdrvGattAttributeUuid *uuid) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 74 : 76;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 74 : 76;
 
     const struct {
         u8 unk;
@@ -494,7 +844,7 @@ Result btdrvAddGattCharacteristic(u8 unk0, u8 unk1, u16 unk2, const BtdrvGattAtt
 Result btdrvAddGattDescriptor(u8 unk0, u16 unk1, const BtdrvGattAttributeUuid *uuid0, const BtdrvGattAttributeUuid *uuid1) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 76 : 78;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 76 : 78;
 
     const struct {
         u8 unk0;
@@ -510,7 +860,7 @@ Result btdrvAddGattDescriptor(u8 unk0, u16 unk1, const BtdrvGattAttributeUuid *u
 Result btdrvGetBleManagedEventInfo(void* buffer, size_t size, u32 *type) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 78 : 79;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 78 : 79;
 
     return _btdrvCmdOutU32OutBuf(buffer, size, type, cmd_id);
 }
@@ -518,7 +868,7 @@ Result btdrvGetBleManagedEventInfo(void* buffer, size_t size, u32 *type) {
 Result btdrvGetGattFirstCharacteristic(bool flag, u32 unk, const BtdrvGattId *id, const BtdrvGattAttributeUuid *uuid, u8 *unk_out, BtdrvGattId *id_out) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 79 : 80;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 79 : 80;
 
     const struct {
         u8 flag;
@@ -545,7 +895,7 @@ Result btdrvGetGattFirstCharacteristic(bool flag, u32 unk, const BtdrvGattId *id
 Result btdrvGetGattNextCharacteristic(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattAttributeUuid *uuid, u8 *unk_out, BtdrvGattId *id_out) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 80 : 81;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 80 : 81;
 
     const struct {
         u8 flag;
@@ -573,7 +923,7 @@ Result btdrvGetGattNextCharacteristic(bool flag, u32 unk, const BtdrvGattId *id0
 Result btdrvGetGattFirstDescriptor(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattAttributeUuid *uuid, BtdrvGattId *id_out) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 81 : 82;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 81 : 82;
 
     const struct {
         u8 flag;
@@ -590,7 +940,7 @@ Result btdrvGetGattFirstDescriptor(bool flag, u32 unk, const BtdrvGattId *id0, c
 Result btdrvGetGattNextDescriptor(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2, const BtdrvGattAttributeUuid *uuid, BtdrvGattId *id_out) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 82 : 83;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 82 : 83;
 
     const struct {
         u8 flag;
@@ -643,7 +993,7 @@ Result btdrvRegisterGattDataPath(const BtdrvGattAttributeUuid *uuid) {
 Result btdrvUnregisterGattDataPath(const BtdrvGattAttributeUuid *uuid) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 83 : 89;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 83 : 89;
 
     return _btdrvCmdInUuidNoOut(uuid, cmd_id);
 }
@@ -651,7 +1001,7 @@ Result btdrvUnregisterGattDataPath(const BtdrvGattAttributeUuid *uuid) {
 Result btdrvReadGattCharacteristic(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 89 : 90;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 89 : 90;
 
     const struct {
         u8 flag;
@@ -668,7 +1018,7 @@ Result btdrvReadGattCharacteristic(bool flag, u8 unk, u32 unk2, const BtdrvGattI
 Result btdrvReadGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 90 : 91;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 90 : 91;
 
     const struct {
         u8 flag;
@@ -686,7 +1036,7 @@ Result btdrvReadGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *i
 Result btdrvWriteGattCharacteristic(bool flag, u8 unk, bool flag2, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const void* buffer, size_t size) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 91 : 92;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 91 : 92;
 
     const struct {
         u8 flag;
@@ -707,7 +1057,7 @@ Result btdrvWriteGattCharacteristic(bool flag, u8 unk, bool flag2, u32 unk2, con
 Result btdrvWriteGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2, const void* buffer, size_t size) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 92 : 93;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 92 : 93;
 
     const struct {
         u8 flag;
@@ -725,18 +1075,6 @@ Result btdrvWriteGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *
     );
 }
 
-static Result _btdrvGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1, u32 cmd_id) {
-    const struct {
-        u8 flag;
-        u8 pad[3];
-        u32 unk;
-        BtdrvGattId id0;
-        BtdrvGattId id1;
-    } in = { flag!=0, {0}, unk, *id0, *id1 };
-
-    return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
-}
-
 Result btdrvRegisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
@@ -747,7 +1085,7 @@ Result btdrvRegisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id0,
 Result btdrvUnregisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 93 : 95;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 93 : 95;
 
     return _btdrvGattNotification(flag, unk, id0, id1, cmd_id);
 }
@@ -755,7 +1093,7 @@ Result btdrvUnregisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id
 Result btdrvGetLeHidEventInfo(void* buffer, size_t size, u32 *type) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 95 : 96;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 95 : 96;
 
     return _btdrvCmdOutU32OutBuf(buffer, size, type, cmd_id);
 }
@@ -763,11 +1101,23 @@ Result btdrvGetLeHidEventInfo(void* buffer, size_t size, u32 *type) {
 Result btdrvRegisterBleHidEvent(Event* out_event) {
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
-    u32 cmd_id = hosversionBefore(6,0,0) ? 96 : 97;
+    u32 cmd_id = hosversionBefore(5,1,0) ? 96 : 97;
 
     return _btdrvCmdGetEvent(out_event, true, cmd_id);
 }
 
+Result btdrvSetBleScanParameter(u16 unk0, u16 unk1) {
+    if (hosversionBefore(5,1,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    const struct {
+        u16 unk0;
+        u16 unk1;
+    } in = { unk0, unk1 };
+
+    return serviceDispatchIn(&g_btdrvSrv, 98, in);
+}
+
 Result btdrvMoveToSecondaryPiconet(BtdrvAddress addr) {
     if (hosversionBefore(10,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);