mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
Added uart.
This commit is contained in:
parent
ab59dfb5bb
commit
f01fb21da5
@ -60,6 +60,7 @@ extern "C" {
|
|||||||
#include "switch/services/lbl.h"
|
#include "switch/services/lbl.h"
|
||||||
#include "switch/services/i2c.h"
|
#include "switch/services/i2c.h"
|
||||||
#include "switch/services/gpio.h"
|
#include "switch/services/gpio.h"
|
||||||
|
#include "switch/services/uart.h"
|
||||||
#include "switch/services/bpc.h"
|
#include "switch/services/bpc.h"
|
||||||
#include "switch/services/pcv.h"
|
#include "switch/services/pcv.h"
|
||||||
#include "switch/services/clkrst.h"
|
#include "switch/services/clkrst.h"
|
||||||
|
243
nx/include/switch/services/uart.h
Normal file
243
nx/include/switch/services/uart.h
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/**
|
||||||
|
* @file uart.h
|
||||||
|
* @brief UART service IPC wrapper.
|
||||||
|
* @author yellows8
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "../types.h"
|
||||||
|
#include "../kernel/event.h"
|
||||||
|
#include "../sf/service.h"
|
||||||
|
|
||||||
|
/// UartPort
|
||||||
|
typedef enum {
|
||||||
|
UartPort_Bluetooth = 1, ///< Bluetooth
|
||||||
|
UartPort_JoyConR = 2, ///< Joy-Con(R)
|
||||||
|
UartPort_JoyConL = 3, ///< Joy-Con(L)
|
||||||
|
UartPort_MCU = 4, ///< MCU
|
||||||
|
} UartPort;
|
||||||
|
|
||||||
|
/// UartPortForDev
|
||||||
|
typedef enum {
|
||||||
|
UartPortForDev_JoyConR = 1, ///< Joy-Con(R)
|
||||||
|
UartPortForDev_JoyConL = 2, ///< Joy-Con(L)
|
||||||
|
UartPortForDev_Bluetooth = 3, ///< Bluetooth
|
||||||
|
} UartPortForDev;
|
||||||
|
|
||||||
|
/// FlowControlMode
|
||||||
|
typedef enum {
|
||||||
|
UartFlowControlMode_None = 0, ///< None
|
||||||
|
UartFlowControlMode_Hardware = 1, ///< Hardware
|
||||||
|
} UartFlowControlMode;
|
||||||
|
|
||||||
|
/// PortEventType
|
||||||
|
typedef enum {
|
||||||
|
UartPortEventType_SendBufferEmpty = 0, ///< SendBufferEmpty
|
||||||
|
UartPortEventType_SendBufferReady = 1, ///< SendBufferReady
|
||||||
|
UartPortEventType_ReceiveBufferReady = 2, ///< ReceiveBufferReady
|
||||||
|
UartPortEventType_ReceiveEnd = 3, ///< ReceiveEnd
|
||||||
|
} UartPortEventType;
|
||||||
|
|
||||||
|
/// PortSession
|
||||||
|
typedef struct {
|
||||||
|
Service s; ///< IPortSession
|
||||||
|
} UartPortSession;
|
||||||
|
|
||||||
|
/// Initialize uart.
|
||||||
|
Result uartInitialize(void);
|
||||||
|
|
||||||
|
/// Exit uart.
|
||||||
|
void uartExit(void);
|
||||||
|
|
||||||
|
/// Gets the Service object for the actual uart service session.
|
||||||
|
Service* uartGetServiceSession(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief HasPort
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartHasPort(UartPort port, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief HasPortForDev
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartHasPortForDev(UartPortForDev port, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedBaudRate
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[in] baud_rate BaudRate
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedBaudRate(UartPort port, u32 baud_rate, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedBaudRateForDev
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[in] baud_rate BaudRate
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedBaudRateForDev(UartPortForDev port, u32 baud_rate, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedFlowControlMode
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[in] flow_control_mode \ref UartFlowControlMode
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedFlowControlMode(UartPort port, UartFlowControlMode flow_control_mode, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedFlowControlModeForDev
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[in] flow_control_mode \ref UartFlowControlMode
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedFlowControlModeForDev(UartPortForDev port, UartFlowControlMode flow_control_mode, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates an \ref UartPortSession.
|
||||||
|
* @note Use \ref uartPortSessionOpenPort or \ref uartPortSessionOpenPortForDev before using any other cmds.
|
||||||
|
* @param[out] s \ref UartPortSession
|
||||||
|
*/
|
||||||
|
Result uartCreatePortSession(UartPortSession *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedPortEvent
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[in] port_event_type \ref UartPortEventType
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedPortEvent(UartPort port, UartPortEventType port_event_type, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedPortEventForDev
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[in] port_event_type \ref UartPortEventType
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedPortEventForDev(UartPortForDev port, UartPortEventType port_event_type, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedDeviceVariation
|
||||||
|
* @note Only available on [7.0.0+].
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[in] device_variation DeviceVariation
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedDeviceVariation(UartPort port, u32 device_variation, bool *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IsSupportedDeviceVariationForDev
|
||||||
|
* @note Only available on [7.0.0+].
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[in] device_variation DeviceVariation
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartIsSupportedDeviceVariationForDev(UartPortForDev port, u32 device_variation, bool *out);
|
||||||
|
|
||||||
|
///@name IPortSession
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close an \ref UartPortSession.
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
*/
|
||||||
|
void uartPortSessionClose(UartPortSession* s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OpenPort
|
||||||
|
* @note This is not usable when the specified \ref UartPort is already being used.
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
* @param[in] port \ref UartPort
|
||||||
|
* @param[in] baud_rate BaudRate
|
||||||
|
* @param[in] flow_control_mode \ref UartFlowControlMode
|
||||||
|
* @param[in] device_variation [7.0.0+] DeviceVariation
|
||||||
|
* @param[in] is_invert_tx [6.0.0+] IsInvertTx
|
||||||
|
* @param[in] is_invert_rx [6.0.0+] IsInvertRx
|
||||||
|
* @param[in] is_invert_rts [6.0.0+] IsInvertRts
|
||||||
|
* @param[in] is_invert_cts [6.0.0+] IsInvertCts
|
||||||
|
* @param[in] send_buffer Send buffer, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] send_buffer_length Send buffer size, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] receive_buffer Receive buffer, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] receive_buffer_length Receive buffer size, must be 0x1000-byte aligned.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionOpenPort(UartPortSession* s, bool *out, UartPort port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, void* send_buffer, u64 send_buffer_length, void* receive_buffer, u64 receive_buffer_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OpenPortForDev
|
||||||
|
* @note See the notes for \ref uartPortSessionOpenPort.
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
* @param[in] port \ref UartPortForDev
|
||||||
|
* @param[in] baud_rate BaudRate
|
||||||
|
* @param[in] flow_control_mode \ref UartFlowControlMode
|
||||||
|
* @param[in] device_variation [7.0.0+] DeviceVariation
|
||||||
|
* @param[in] is_invert_tx [6.0.0+] IsInvertTx
|
||||||
|
* @param[in] is_invert_rx [6.0.0+] IsInvertRx
|
||||||
|
* @param[in] is_invert_rts [6.0.0+] IsInvertRts
|
||||||
|
* @param[in] is_invert_cts [6.0.0+] IsInvertCts
|
||||||
|
* @param[in] send_buffer Send buffer, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] send_buffer_length Send buffer size, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] receive_buffer Receive buffer, must be 0x1000-byte aligned.
|
||||||
|
* @param[in] receive_buffer_length Receive buffer size, must be 0x1000-byte aligned.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionOpenPortForDev(UartPortSession* s, bool *out, UartPortForDev port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, void* send_buffer, u64 send_buffer_length, void* receive_buffer, u64 receive_buffer_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GetWritableLength
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[out] out Output WritableLength.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionGetWritableLength(UartPortSession* s, u64 *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[in] in_data Input data buffer.
|
||||||
|
* @param[in] size Input data buffer size.
|
||||||
|
* @param[out] out Output size.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionSend(UartPortSession* s, const void* in_data, size_t size, u64 *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GetReadableLength
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[out] out Output ReadableLength.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionGetReadableLength(UartPortSession* s, u64 *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Receive
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[out] out_data Output data buffer.
|
||||||
|
* @param[in] size Output data buffer size.
|
||||||
|
* @param[out] out Output size.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionReceive(UartPortSession* s, void* out_data, size_t size, u64 *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief BindPortEvent
|
||||||
|
* @note The Event must be closed by the user after using \ref uartPortSessionUnbindPortEvent.
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[in] port_event_type \ref UartPortEventType
|
||||||
|
* @param[in] threshold Threshold
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
* @param[out] out_event Output Event with autoclear=false.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionBindPortEvent(UartPortSession* s, UartPortEventType port_event_type, s64 threshold, bool *out, Event *out_event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UnbindPortEvent
|
||||||
|
* @param s \ref UartPortSession
|
||||||
|
* @param[in] port_event_type \ref UartPortEventType
|
||||||
|
* @param[out] out Output success flag.
|
||||||
|
*/
|
||||||
|
Result uartPortSessionUnbindPortEvent(UartPortSession* s, UartPortEventType port_event_type, bool *out);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
258
nx/source/services/uart.c
Normal file
258
nx/source/services/uart.c
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||||
|
#include <string.h>
|
||||||
|
#include "service_guard.h"
|
||||||
|
#include "runtime/hosversion.h"
|
||||||
|
#include "kernel/tmem.h"
|
||||||
|
#include "services/uart.h"
|
||||||
|
|
||||||
|
static Service g_uartSrv;
|
||||||
|
|
||||||
|
NX_GENERATE_SERVICE_GUARD(uart);
|
||||||
|
|
||||||
|
Result _uartInitialize(void) {
|
||||||
|
return smGetService(&g_uartSrv, "uart");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _uartCleanup(void) {
|
||||||
|
serviceClose(&g_uartSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Service* uartGetServiceSession(void) {
|
||||||
|
return &g_uartSrv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _uartCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) {
|
||||||
|
return serviceDispatchOut(srv, cmd_id, *out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _uartCmdInU32OutBool(Service* srv, u32 inval, bool *out, u32 cmd_id) {
|
||||||
|
u8 tmp=0;
|
||||||
|
Result rc = serviceDispatchInOut(srv, cmd_id, inval, tmp);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _uartCmdInTwoU32sOutBool(Service* srv, u32 inval0, u32 inval1, bool *out, u32 cmd_id) {
|
||||||
|
const struct {
|
||||||
|
u32 inval0;
|
||||||
|
u32 inval1;
|
||||||
|
} in = { inval0, inval1 };
|
||||||
|
|
||||||
|
u8 tmp=0;
|
||||||
|
Result rc = serviceDispatchInOut(srv, cmd_id, in, tmp);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartHasPort(UartPort port, bool *out) {
|
||||||
|
return _uartCmdInU32OutBool(&g_uartSrv, port, out, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartHasPortForDev(UartPortForDev port, bool *out) {
|
||||||
|
return _uartCmdInU32OutBool(&g_uartSrv, port, out, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedBaudRate(UartPort port, u32 baud_rate, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, baud_rate, out, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedBaudRateForDev(UartPortForDev port, u32 baud_rate, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, baud_rate, out, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedFlowControlMode(UartPort port, UartFlowControlMode flow_control_mode, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, flow_control_mode, out, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedFlowControlModeForDev(UartPortForDev port, UartFlowControlMode flow_control_mode, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, flow_control_mode, out, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartCreatePortSession(UartPortSession *s) {
|
||||||
|
return serviceDispatch(&g_uartSrv, 6,
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = &s->s,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedPortEvent(UartPort port, UartPortEventType port_event_type, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, port_event_type, out, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedPortEventForDev(UartPortForDev port, UartPortEventType port_event_type, bool *out) {
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, port_event_type, out, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedDeviceVariation(UartPort port, u32 device_variation, bool *out) {
|
||||||
|
if (hosversionBefore(7,0,0))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, device_variation, out, 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartIsSupportedDeviceVariationForDev(UartPortForDev port, u32 device_variation, bool *out) {
|
||||||
|
if (hosversionBefore(7,0,0))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
|
||||||
|
return _uartCmdInTwoU32sOutBool(&g_uartSrv, port, device_variation, out, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPortSession
|
||||||
|
|
||||||
|
void uartPortSessionClose(UartPortSession* s) {
|
||||||
|
serviceClose(&s->s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pre-6.0.0
|
||||||
|
static Result _uartPortSessionOpenPort_v1(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length, u32 cmd_id) {
|
||||||
|
const struct {
|
||||||
|
u32 port;
|
||||||
|
u32 baud_rate;
|
||||||
|
u32 flow_control_mode;
|
||||||
|
u32 pad;
|
||||||
|
u64 send_buffer_length;
|
||||||
|
u64 receive_buffer_length;
|
||||||
|
} in = { port, baud_rate, flow_control_mode, 0, send_buffer_length, receive_buffer_length };
|
||||||
|
|
||||||
|
u8 tmp=0;
|
||||||
|
Result rc = serviceDispatchInOut(&s->s, cmd_id, in, tmp,
|
||||||
|
.in_num_handles = 2,
|
||||||
|
.in_handles = { send_handle, receive_handle },
|
||||||
|
);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 6.x
|
||||||
|
static Result _uartPortSessionOpenPort_v6(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length, u32 cmd_id) {
|
||||||
|
const struct {
|
||||||
|
u8 is_invert_tx;
|
||||||
|
u8 is_invert_rx;
|
||||||
|
u8 is_invert_rts;
|
||||||
|
u8 is_invert_cts;
|
||||||
|
u32 port;
|
||||||
|
u32 baud_rate;
|
||||||
|
u32 flow_control_mode;
|
||||||
|
u64 send_buffer_length;
|
||||||
|
u64 receive_buffer_length;
|
||||||
|
} in = { is_invert_tx!=0, is_invert_rx!=0, is_invert_rts!=0, is_invert_cts!=0, port, baud_rate, flow_control_mode, send_buffer_length, receive_buffer_length };
|
||||||
|
|
||||||
|
u8 tmp=0;
|
||||||
|
Result rc = serviceDispatchInOut(&s->s, cmd_id, in, tmp,
|
||||||
|
.in_num_handles = 2,
|
||||||
|
.in_handles = { send_handle, receive_handle },
|
||||||
|
);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [7.0.0+]
|
||||||
|
static Result _uartPortSessionOpenPort_v7(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length, u32 cmd_id) {
|
||||||
|
const struct {
|
||||||
|
u8 is_invert_tx;
|
||||||
|
u8 is_invert_rx;
|
||||||
|
u8 is_invert_rts;
|
||||||
|
u8 is_invert_cts;
|
||||||
|
u32 port;
|
||||||
|
u32 baud_rate;
|
||||||
|
u32 flow_control_mode;
|
||||||
|
u32 device_variation;
|
||||||
|
u32 pad;
|
||||||
|
u64 send_buffer_length;
|
||||||
|
u64 receive_buffer_length;
|
||||||
|
} in = { is_invert_tx!=0, is_invert_rx!=0, is_invert_rts!=0, is_invert_cts!=0, port, baud_rate, flow_control_mode, device_variation, 0, send_buffer_length, receive_buffer_length };
|
||||||
|
|
||||||
|
u8 tmp=0;
|
||||||
|
Result rc = serviceDispatchInOut(&s->s, cmd_id, in, tmp,
|
||||||
|
.in_num_handles = 2,
|
||||||
|
.in_handles = { send_handle, receive_handle },
|
||||||
|
);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _uartPortSessionOpenPort(UartPortSession* s, bool *out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, Handle send_handle, Handle receive_handle, u64 send_buffer_length, u64 receive_buffer_length, u32 cmd_id) {
|
||||||
|
if (hosversionBefore(6,0,0))
|
||||||
|
return _uartPortSessionOpenPort_v1(s, out, port, baud_rate, flow_control_mode, send_handle, receive_handle, send_buffer_length, receive_buffer_length, cmd_id);
|
||||||
|
else if (hosversionBefore(7,0,0)) // 6.x
|
||||||
|
return _uartPortSessionOpenPort_v6(s, out, port, baud_rate, flow_control_mode, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length, cmd_id);
|
||||||
|
else // [7.0.0+]
|
||||||
|
return _uartPortSessionOpenPort_v7(s, out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle, receive_handle, send_buffer_length, receive_buffer_length, cmd_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionOpenPort(UartPortSession* s, bool *out, UartPort port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, void* send_buffer, u64 send_buffer_length, void* receive_buffer, u64 receive_buffer_length) {
|
||||||
|
Result rc=0;
|
||||||
|
TransferMemory send_tmem={0};
|
||||||
|
TransferMemory receive_tmem={0};
|
||||||
|
|
||||||
|
rc = tmemCreateFromMemory(&send_tmem, send_buffer, send_buffer_length, Perm_R | Perm_W);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = tmemCreateFromMemory(&receive_tmem, receive_buffer, send_buffer_length, Perm_R | Perm_W);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = _uartPortSessionOpenPort(s, out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_tmem.handle, receive_tmem.handle, send_buffer_length, receive_buffer_length, 0);
|
||||||
|
|
||||||
|
tmemClose(&send_tmem);
|
||||||
|
tmemClose(&receive_tmem);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionOpenPortForDev(UartPortSession* s, bool *out, UartPortForDev port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, void* send_buffer, u64 send_buffer_length, void* receive_buffer, u64 receive_buffer_length) {
|
||||||
|
Result rc=0;
|
||||||
|
TransferMemory send_tmem={0};
|
||||||
|
TransferMemory receive_tmem={0};
|
||||||
|
|
||||||
|
rc = tmemCreateFromMemory(&send_tmem, send_buffer, send_buffer_length, Perm_R | Perm_W);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = tmemCreateFromMemory(&receive_tmem, receive_buffer, send_buffer_length, Perm_R | Perm_W);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = _uartPortSessionOpenPort(s, out, port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_tmem.handle, receive_tmem.handle, send_buffer_length, receive_buffer_length, 1);
|
||||||
|
|
||||||
|
tmemClose(&send_tmem);
|
||||||
|
tmemClose(&receive_tmem);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionGetWritableLength(UartPortSession* s, u64 *out) {
|
||||||
|
return _uartCmdNoInOutU64(&s->s, out, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionSend(UartPortSession* s, const void* in_data, size_t size, u64 *out_size) {
|
||||||
|
return serviceDispatchOut(&s->s, 3, *out_size,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
|
||||||
|
.buffers = { { in_data, size } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionGetReadableLength(UartPortSession* s, u64 *out) {
|
||||||
|
return _uartCmdNoInOutU64(&s->s, out, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionReceive(UartPortSession* s, void* out_data, size_t size, u64 *out_size) {
|
||||||
|
return serviceDispatchOut(&s->s, 5, *out_size,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
|
.buffers = { { out_data, size } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionBindPortEvent(UartPortSession* s, UartPortEventType port_event_type, s64 threshold, bool *out, Event *out_event) {
|
||||||
|
const struct {
|
||||||
|
u32 port_event_type;
|
||||||
|
u32 pad;
|
||||||
|
s64 threshold;
|
||||||
|
} in = { port_event_type, 0, threshold };
|
||||||
|
|
||||||
|
u8 tmp=0;
|
||||||
|
Handle tmp_handle=0;
|
||||||
|
Result rc = serviceDispatchInOut(&s->s, 6, in, tmp,
|
||||||
|
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||||
|
.out_handles = &tmp_handle,
|
||||||
|
);
|
||||||
|
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
|
||||||
|
if (R_SUCCEEDED(rc) && out_event) eventLoadRemote(out_event, tmp_handle, false);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result uartPortSessionUnbindPortEvent(UartPortSession* s, UartPortEventType port_event_type, bool *out) {
|
||||||
|
return _uartCmdInU32OutBool(&s->s, port_event_type, out, 7);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user