mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
Added initial bluetooth support.
This commit is contained in:
parent
bcc0f86aa3
commit
a5e8572019
@ -93,6 +93,8 @@ extern "C" {
|
||||
#include "switch/services/set.h"
|
||||
#include "switch/services/ssl.h"
|
||||
#include "switch/services/lr.h"
|
||||
#include "switch/services/bt.h"
|
||||
#include "switch/services/btdrv.h"
|
||||
#include "switch/services/spl.h"
|
||||
#include "switch/services/ncm.h"
|
||||
#include "switch/services/psc.h"
|
||||
|
131
nx/include/switch/services/bt.h
Normal file
131
nx/include/switch/services/bt.h
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file bt.h
|
||||
* @brief Bluetooth user (bt) service IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../services/btdrv.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// Initialize bt. Only available on [5.0.0+].
|
||||
Result btInitialize(void);
|
||||
|
||||
/// Exit bt.
|
||||
void btExit(void);
|
||||
|
||||
/// Gets the Service object for the actual bt service session.
|
||||
Service* btGetServiceSession(void);
|
||||
|
||||
/**
|
||||
* @brief LeClientReadCharacteristic
|
||||
* @note This is essentially the same as \ref btdrvReadGattCharacteristic.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btLeClientReadCharacteristic(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief LeClientReadDescriptor
|
||||
* @note This is essentially the same as \ref btdrvReadGattDescriptor.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] id2 \ref BtdrvGattId
|
||||
*/
|
||||
Result btLeClientReadDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2);
|
||||
|
||||
/**
|
||||
* @brief LeClientWriteCharacteristic
|
||||
* @note This is essentially the same as \ref btdrvWriteGattCharacteristic.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] flag2 Flag
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btLeClientWriteCharacteristic(bool flag, u8 unk, bool flag2, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief LeClientWriteDescriptor
|
||||
* @note This is essentially the same as \ref btdrvWriteGattDescriptor.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] id2 \ref BtdrvGattId
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btLeClientWriteDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief LeClientRegisterNotification
|
||||
* @note This is essentially the same as \ref btdrvRegisterGattNotification.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btLeClientRegisterNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief LeClientDeregisterNotification
|
||||
* @note This is essentially the same as \ref btdrvUnregisterGattNotification.
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btLeClientDeregisterNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief SetLeResponse
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] uuid0 \ref BtdrvGattAttributeUuid
|
||||
* @param[in] uuid1 \ref BtdrvGattAttributeUuid
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btSetLeResponse(u8 unk, const BtdrvGattAttributeUuid *uuid0, const BtdrvGattAttributeUuid *uuid1, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief LeSendIndication
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] flag Flag
|
||||
* @param[in] uuid0 \ref BtdrvGattAttributeUuid
|
||||
* @param[in] uuid1 \ref BtdrvGattAttributeUuid
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btLeSendIndication(u8 unk, bool flag, const BtdrvGattAttributeUuid *uuid0, const BtdrvGattAttributeUuid *uuid1, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief GetLeEventInfo
|
||||
* @note This is identical to \ref btdrvGetLeEventInfo except different state is used.
|
||||
* @note The state used by this is reset after writing the data to output.
|
||||
* @param[in] buffer Output buffer. 0x400-bytes from state is written here.
|
||||
* @param[in] size Output buffer size.
|
||||
* @oaram[out] type Output BleEventType.
|
||||
*/
|
||||
Result btGetLeEventInfo(void* buffer, size_t size, u32 *type);
|
||||
|
||||
/**
|
||||
* @brief RegisterBleEvent
|
||||
* @note This is identical to \ref btdrvRegisterBleHidEvent except different state is used.
|
||||
* @note The Event must be closed by the user once finished with it.
|
||||
* @param[out] out_event Output Event with autoclear=true.
|
||||
*/
|
||||
Result btRegisterBleEvent(Event* out_event);
|
||||
|
181
nx/include/switch/services/btdrv.h
Normal file
181
nx/include/switch/services/btdrv.h
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @file btdrv.h
|
||||
* @brief Bluetooth driver (btdrv) service IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// Address
|
||||
typedef struct {
|
||||
u8 address[0x6]; ///< Address
|
||||
} BtdrvAddress;
|
||||
|
||||
/// AdapterProperty
|
||||
typedef struct {
|
||||
u8 unk_x0[0x103]; ///< Unknown
|
||||
} 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;
|
||||
|
||||
/// BleAdvertisePacketData
|
||||
typedef struct {
|
||||
u8 unk_x0[0xCC]; ///< Unknown
|
||||
} BtdrvBleAdvertisePacketData;
|
||||
|
||||
/// BleAdvertiseFilter
|
||||
typedef struct {
|
||||
u8 unk_x0[0x3E]; ///< Unknown
|
||||
} BtdrvBleAdvertiseFilter;
|
||||
|
||||
/// GattAttributeUuid
|
||||
typedef struct {
|
||||
u8 unk_x0[0x14]; ///< Unknown
|
||||
} BtdrvGattAttributeUuid;
|
||||
|
||||
/// GattId
|
||||
typedef struct {
|
||||
u8 unk_x0[0x18]; ///< Unknown
|
||||
} BtdrvGattId;
|
||||
|
||||
/// Initialize btdrv.
|
||||
Result btdrvInitialize(void);
|
||||
|
||||
/// Exit btdrv.
|
||||
void btdrvExit(void);
|
||||
|
||||
/// Gets the Service object for the actual btdrv service session.
|
||||
Service* btdrvGetServiceSession(void);
|
||||
|
||||
/**
|
||||
* @brief ReadGattCharacteristic
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btdrvReadGattCharacteristic(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief ReadGattDescriptor
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] id2 \ref BtdrvGattId
|
||||
*/
|
||||
Result btdrvReadGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2);
|
||||
|
||||
/**
|
||||
* @brief WriteGattCharacteristic
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] flag2 Flag
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btdrvWriteGattCharacteristic(bool flag, u8 unk, bool flag2, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief WriteGattDescriptor
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] unk2 Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
* @param[in] id2 \ref BtdrvGattId
|
||||
* @param[in] buffer Input buffer.
|
||||
* @param[in] size Input buffer size.
|
||||
*/
|
||||
Result btdrvWriteGattDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief RegisterGattNotification
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btdrvRegisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief UnregisterGattNotification
|
||||
* @note Only available on [5.0.0+].
|
||||
* @param[in] flag Flag
|
||||
* @param[in] unk Unknown
|
||||
* @param[in] id0 \ref BtdrvGattId
|
||||
* @param[in] id1 \ref BtdrvGattId
|
||||
*/
|
||||
Result btdrvUnregisterGattNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1);
|
||||
|
||||
/**
|
||||
* @brief GetLeEventInfo
|
||||
* @note Only available on [5.0.0+].
|
||||
* @note The state used by this is reset after writing the data to output.
|
||||
* @param[in] buffer Output buffer. 0x400-bytes from state is written here.
|
||||
* @param[in] size Output buffer size.
|
||||
* @oaram[out] type Output BleEventType.
|
||||
*/
|
||||
Result btdrvGetLeEventInfo(void* buffer, size_t size, u32 *type);
|
||||
|
||||
/**
|
||||
* @brief RegisterBleHidEvent
|
||||
* @note Only available on [5.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 btdrvRegisterBleHidEvent(Event* out_event);
|
||||
|
178
nx/source/services/bt.c
Normal file
178
nx/source/services/bt.c
Normal file
@ -0,0 +1,178 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/bt.h"
|
||||
#include "services/applet.h"
|
||||
|
||||
static Service g_btSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(bt);
|
||||
|
||||
Result _btInitialize(void) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
return smGetService(&g_btSrv, "bt");
|
||||
}
|
||||
|
||||
void _btCleanup(void) {
|
||||
serviceClose(&g_btSrv);
|
||||
}
|
||||
|
||||
Service* btGetServiceSession(void) {
|
||||
return &g_btSrv;
|
||||
}
|
||||
|
||||
Result btLeClientReadCharacteristic(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1) {
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 0, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btLeClientReadDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2) {
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
BtdrvGattId id2;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1, *id2, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 1, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btLeClientWriteCharacteristic(bool flag, u8 unk, bool flag2, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const void* buffer, size_t size) {
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 flag2;
|
||||
u8 pad;
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { flag!=0, unk, flag2!=0, 0, unk2, *id0, *id1, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 2, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btLeClientWriteDescriptor(bool flag, u8 unk, u32 unk2, const BtdrvGattId *id0, const BtdrvGattId *id1, const BtdrvGattId *id2, const void* buffer, size_t size) {
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
BtdrvGattId id2;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1, *id2, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 3, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _btLeClientNotification(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;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { flag!=0, {0}, unk, *id0, *id1, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, cmd_id, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btLeClientRegisterNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1) {
|
||||
return _btLeClientNotification(flag, unk, id0, id1, 4);
|
||||
}
|
||||
|
||||
Result btLeClientDeregisterNotification(bool flag, u32 unk, const BtdrvGattId *id0, const BtdrvGattId *id1) {
|
||||
return _btLeClientNotification(flag, unk, id0, id1, 5);
|
||||
}
|
||||
|
||||
Result btSetLeResponse(u8 unk, const BtdrvGattAttributeUuid *uuid0, const BtdrvGattAttributeUuid *uuid1, const void* buffer, size_t size) {
|
||||
const struct {
|
||||
u8 unk;
|
||||
u8 pad[3];
|
||||
BtdrvGattAttributeUuid uuid0;
|
||||
BtdrvGattAttributeUuid uuid1;
|
||||
u8 pad2[4];
|
||||
u64 AppletResourceUserId;
|
||||
} in = { unk, {0}, *uuid0, *uuid1, {0}, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 6, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btLeSendIndication(u8 unk, bool flag, const BtdrvGattAttributeUuid *uuid0, const BtdrvGattAttributeUuid *uuid1, const void* buffer, size_t size) {
|
||||
const struct {
|
||||
u8 unk;
|
||||
u8 flag;
|
||||
u8 pad[2];
|
||||
BtdrvGattAttributeUuid uuid0;
|
||||
BtdrvGattAttributeUuid uuid1;
|
||||
u8 pad2[4];
|
||||
u64 AppletResourceUserId;
|
||||
} in = { unk, flag!=0, {0}, *uuid0, *uuid1, {0}, appletGetAppletResourceUserId() };
|
||||
|
||||
return serviceDispatchIn(&g_btSrv, 7, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btGetLeEventInfo(void* buffer, size_t size, u32 *type) {
|
||||
u64 AppletResourceUserId = appletGetAppletResourceUserId();
|
||||
return serviceDispatchInOut(&g_btSrv, 8, AppletResourceUserId, *type,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result btRegisterBleEvent(Event* out_event) {
|
||||
Handle tmp_handle = INVALID_HANDLE;
|
||||
Result rc = 0;
|
||||
u64 AppletResourceUserId = appletGetAppletResourceUserId();
|
||||
|
||||
rc = serviceDispatchIn(&g_btSrv, 9, AppletResourceUserId,
|
||||
.in_send_pid = true,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &tmp_handle,
|
||||
);
|
||||
if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, true);
|
||||
return rc;
|
||||
}
|
||||
|
153
nx/source/services/btdrv.c
Normal file
153
nx/source/services/btdrv.c
Normal file
@ -0,0 +1,153 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/btdrv.h"
|
||||
|
||||
static Service g_btdrvSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(btdrv);
|
||||
|
||||
Result _btdrvInitialize(void) {
|
||||
return smGetService(&g_btdrvSrv, "btdrv");
|
||||
}
|
||||
|
||||
void _btdrvCleanup(void) {
|
||||
serviceClose(&g_btdrvSrv);
|
||||
}
|
||||
|
||||
Service* btdrvGetServiceSession(void) {
|
||||
return &g_btdrvSrv;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1};
|
||||
|
||||
return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
BtdrvGattId id2;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1, *id2 };
|
||||
|
||||
return serviceDispatchIn(&g_btdrvSrv, cmd_id, in);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 flag2;
|
||||
u8 pad;
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
} in = { flag!=0, unk, flag2!=0, 0, unk2, *id0, *id1 };
|
||||
|
||||
return serviceDispatchIn(&g_btdrvSrv, cmd_id, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const struct {
|
||||
u8 flag;
|
||||
u8 unk;
|
||||
u8 pad[2];
|
||||
u32 unk2;
|
||||
BtdrvGattId id0;
|
||||
BtdrvGattId id1;
|
||||
BtdrvGattId id2;
|
||||
} in = { flag!=0, unk, {0}, unk2, *id0, *id1, *id2 };
|
||||
|
||||
return serviceDispatchIn(&g_btdrvSrv, cmd_id, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return _btdrvGattNotification(flag, unk, id0, id1, 94);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return _btdrvGattNotification(flag, unk, id0, id1, cmd_id);
|
||||
}
|
||||
|
||||
Result btdrvGetLeEventInfo(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;
|
||||
|
||||
return serviceDispatchOut(&g_btdrvSrv, cmd_id, *type,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Handle tmp_handle = INVALID_HANDLE;
|
||||
Result rc = 0;
|
||||
|
||||
rc = serviceDispatch(&g_btdrvSrv, cmd_id,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &tmp_handle,
|
||||
);
|
||||
if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, true);
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user