Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nx/include/switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ extern "C" {
#include "switch/services/avm.h"
#include "switch/services/mm.h"
#include "switch/services/omm.h"
#include "switch/services/ovln.h"

#include "switch/display/binder.h"
#include "switch/display/parcel.h"
Expand Down
153 changes: 153 additions & 0 deletions nx/include/switch/services/ovln.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* @file ovln.h
* @brief Overlay notification (ovln:*) service IPC wrapper.
* @author ndeadly
* @copyright libnx Authors
*/
#pragma once
#include "../sf/service.h"
#include "../kernel/event.h"

/// EnqueuePosition
typedef enum {
OvlnEnqueuePosition_Front = 0,
OvlnEnqueuePosition_Back = 1,
} OvlnEnqueuePosition;

/// OverflowOption
typedef enum {
OvlnOverflowOption_Error = 0,
OvlnOverflowOption_RemoveFront = 1,
OvlnOverflowOption_RemoveBack = 2,
OvlnOverflowOption_Block = 3,
} OvlnOverflowOption;

/// SourceName
typedef struct {
char name[0x10]; ///< Source name. Official software always uses the name "overlay".
} OvlnSourceName;

/// RawMessage
typedef struct {
u32 tag; ///< Unique tag specifying the message type.
u32 data_size; ///< Size of the below data.
u8 data[0x78]; ///< Message data.
} OvlnRawMessage;

/// QueueAttribute
typedef struct {
u32 queue_length; ///< Length of send queue.
u8 reserved[4]; ///< Reserved.
} OvlnQueueAttribute;

/// SendOption
typedef struct {
u8 enqueue_position; ///< \ref OvlnEnqueuePosition
u8 overflow_option; ///< \ref OvlnOverflowOption
u8 reserved[6]; ///< Reserved.
} OvlnSendOption;

/// Receiver
typedef struct {
Service s; ///< IReceiver
} OvlnReceiver;

/// Sender
typedef struct {
Service s; ///< ISender
} OvlnSender;

/// Initialize ovln:rcv.
Result ovlnrcvInitialize(void);

/// Exit ovln:rcv.
void ovlnrcvExit(void);

/// Initialize ovln:snd.
Result ovlnsndInitialize(void);

/// Exit ovln:snd.
void ovlnsndExit(void);

/// Gets the Service object for the actual ovln:rcv service session.
Service* ovlnrcvGetServiceSession(void);

/// Gets the Service object for the actual ovln:snd service session.
Service* ovlnsndGetServiceSession(void);

/**
* @brief OpenReceiver
* @param[out] r \ref OvlnReceiver
*/
Result ovlnrcvOpenReceiver(OvlnReceiver *r);

/**
* @brief CloseReceiver
* @param[in] r \ref OvlnReceiver
*/
void ovlnrcvCloseReceiver(OvlnReceiver *r);

/**
* @brief AddSource
* @param[in] r \ref OvlnReceiver
* @param[in] name \ref OvlnSourceName
*/
Result ovlnrcvAddSource(OvlnReceiver *r, const OvlnSourceName *name);

/**
* @brief RemoveSource
* @param[in] r \ref OvlnReceiver
* @param[in] name \ref OvlnSourceName
*/
Result ovlnrcvRemoveSource(OvlnReceiver *r, const OvlnSourceName *name);

/**
* @brief GetReceiveEventHandle
* @param[in] r \ref OvlnReceiver
* @param[out] out_event Output Event with autoclear=true.
*/
Result ovlnrcvGetReceiveEventHandle(OvlnReceiver *r, Event* out_event);

/**
* @brief Receive
* @param[in] r \ref OvlnReceiver
* @param[out] message \ref OvlnRawMessage
*/
Result ovlnrcvReceive(OvlnReceiver *r, OvlnRawMessage *message);

/**
* @brief ReceiveWithTick
* @param[in] r \ref OvlnReceiver
* @param[out] message \ref OvlnRawMessage
* @param[out] tick System tick.
*/
Result ovlnrcvReceiveWithTick(OvlnReceiver *r, OvlnRawMessage *message, s64 *tick);

/**
* @brief OpenSender
* @param[in] s \ref OvlnSender
* @param[in] name \ref OvlnSourceName
* @param[in] attribute \ref OvlnQueueAttribute
*/
Result ovlnsndOpenSender(OvlnSender *s, const OvlnSourceName *name, OvlnQueueAttribute attribute);

/**
* @brief CloseSender
* @param[in] s \ref OvlnSender
*/
void ovlnsndCloseSender(OvlnSender *s);

/**
* @brief Send
* @param[in] s \ref OvlnSender
* @param[in] option \ref OvlnSendOption
* @param[in] message \ref OvlnRawMessage
*/
Result ovlnsndSend(OvlnSender *s, OvlnSendOption option, const OvlnRawMessage *message);

/**
* @brief GetUnreceivedMessageCount
* @param[in] s \ref OvlnSender
* @param[out] count number of unreceived messages.
*/
Result ovlnsndGetUnreceivedMessageCount(OvlnSender *s, u32 *count);
111 changes: 111 additions & 0 deletions nx/source/services/ovln.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "service_guard.h"
#include "services/ovln.h"

static Service g_ovlnrcvSrv;
static Service g_ovlnsndSrv;

NX_GENERATE_SERVICE_GUARD(ovlnrcv);
NX_GENERATE_SERVICE_GUARD(ovlnsnd);

Result _ovlnrcvInitialize(void) {
return smGetService(&g_ovlnrcvSrv, "ovln:rcv");
}

void _ovlnrcvCleanup(void) {
serviceClose(&g_ovlnrcvSrv);
}

Result _ovlnsndInitialize(void) {
return smGetService(&g_ovlnsndSrv, "ovln:snd");
}

void _ovlnsndCleanup(void) {
serviceClose(&g_ovlnsndSrv);
}

Service* ovlnrcvGetServiceSession(void) {
return &g_ovlnrcvSrv;
}

Service* ovlnsndGetServiceSession(void) {
return &g_ovlnsndSrv;
}

Result ovlnrcvOpenReceiver(OvlnReceiver *receiver) {
return serviceDispatch(&g_ovlnrcvSrv, 0,
.out_num_objects = 1,
.out_objects = &receiver->s,
);
}

void ovlnrcvCloseReceiver(OvlnReceiver *r) {
serviceClose(&r->s);
}

Result ovlnrcvAddSource(OvlnReceiver *r, const OvlnSourceName *name) {
return serviceDispatchIn(&r->s, 0, *name);
}

Result ovlnrcvRemoveSource(OvlnReceiver *r, const OvlnSourceName *name) {
return serviceDispatchIn(&r->s, 1, *name);
}

Result ovlnrcvGetReceiveEventHandle(OvlnReceiver *r, Event* out_event) {
Handle tmp_handle = INVALID_HANDLE;

Result rc = serviceDispatch(&r->s, 2,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = &tmp_handle,
);
if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, true);
return rc;
}

Result ovlnrcvReceive(OvlnReceiver *r, OvlnRawMessage *message) {
return serviceDispatchOut(&r->s, 3, *message);
}

Result ovlnrcvReceiveWithTick(OvlnReceiver *r, OvlnRawMessage *message, s64 *tick) {
struct {
OvlnRawMessage message;
s64 tick;
} out;

Result rc = serviceDispatchOut(&r->s, 4, out);
if (R_SUCCEEDED(rc)) {
*message = out.message;
*tick = out.tick;
}

return rc;
}

Result ovlnsndOpenSender(OvlnSender *s, const OvlnSourceName *name, OvlnQueueAttribute attribute) {
const struct {
OvlnSourceName name;
OvlnQueueAttribute attribute;
} in = { *name, attribute };

return serviceDispatchIn(&g_ovlnsndSrv, 0, in,
.out_num_objects = 1,
.out_objects = &s->s,
);
}

void ovlnsndCloseSender(OvlnSender *s) {
serviceClose(&s->s);
}

Result ovlnsndSend(OvlnSender *s, OvlnSendOption option, const OvlnRawMessage *message) {
const struct {
OvlnSendOption option;
OvlnRawMessage message;
} in = { option, *message };

return serviceDispatchIn(&s->s, 0, in);
}

Result ovlnsndGetUnreceivedMessageCount(OvlnSender *s, u32 *count) {
return serviceDispatchOut(&s->s, 1, *count);
}
Loading