From e02b6c167ab282b3d0f13b478591fe293cdc4831 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 8 Feb 2019 19:47:13 -0500 Subject: [PATCH] Added capssu and caps.h. --- nx/include/switch.h | 2 + nx/include/switch/services/caps.h | 19 ++++++ nx/include/switch/services/capssu.h | 21 +++++++ nx/source/services/capssu.c | 97 +++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 nx/include/switch/services/caps.h create mode 100644 nx/include/switch/services/capssu.h create mode 100644 nx/source/services/capssu.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 807f16e5..857a361f 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -81,6 +81,8 @@ extern "C" { #include "switch/services/spl.h" #include "switch/services/ncm.h" #include "switch/services/psc.h" +#include "switch/services/caps.h" +#include "switch/services/capssu.h" #include "switch/display/binder.h" #include "switch/display/parcel.h" diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h new file mode 100644 index 00000000..4e8890f8 --- /dev/null +++ b/nx/include/switch/services/caps.h @@ -0,0 +1,19 @@ +/** + * @file caps.h + * @brief Common caps (caps:*) service IPC header. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" + +typedef struct { + u32 unk_x0; + u8 unk_x4[0x3c]; +} CapsScreenShotAttribute; + +typedef struct { + u8 unk_x0[0x20]; +} CapsApplicationAlbumEntry; + diff --git a/nx/include/switch/services/capssu.h b/nx/include/switch/services/capssu.h new file mode 100644 index 00000000..3e4bef51 --- /dev/null +++ b/nx/include/switch/services/capssu.h @@ -0,0 +1,21 @@ +/** + * @file capssu.h + * @brief Application screenshot saving (caps:su) service IPC wrapper. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" +#include "../services/caps.h" + +/// Initialize caps:su. Only available on 6.0.0+. +Result capssuInitialize(void); +void capssuExit(void); + +/// Same as \ref capssuSaveScreenShotEx0, except this uses an all-zero CapsScreenShotAttribute where the first u32 is set to attr_val. attr_val can be zero. +Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out); + +/// Saves an Album screenshot using the specified gfx data in buffer (1280x720 RGBA8), size must be at least 0x384000. unk can be zero. +Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out); + diff --git a/nx/source/services/capssu.c b/nx/source/services/capssu.c new file mode 100644 index 00000000..6dedaa75 --- /dev/null +++ b/nx/source/services/capssu.c @@ -0,0 +1,97 @@ +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "services/applet.h" +#include "services/caps.h" +#include "services/capssu.h" +#include "services/sm.h" + +static Service g_capssuSrv; +static u64 g_capssuRefCnt; + +Result capssuInitialize(void) { + Result rc=0; + + atomicIncrement64(&g_capssuRefCnt); + + if (serviceIsActive(&g_capssuSrv)) + return 0; + + if (!kernelAbove600()) + rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (R_SUCCEEDED(rc)) rc = smGetService(&g_capssuSrv, "caps:su"); + + if (R_FAILED(rc)) capssuExit(); + + return rc; +} + +void capssuExit(void) { + if (atomicDecrement64(&g_capssuRefCnt) == 0) + serviceClose(&g_capssuSrv); +} + +static Result _capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) { + u64 AppletResourceUserId = 0; + appletGetAppletResourceUserId(&AppletResourceUserId); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + CapsScreenShotAttribute attr; + u32 unk; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + ipcAddSendBuffer(&c, buffer, size, 1); + + raw = serviceIpcPrepareHeader(&g_capssuSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 203; + raw->attr = *attr; + raw->unk = unk; + raw->AppletResourceUserId = AppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_capssuSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + CapsApplicationAlbumEntry out; + } *resp; + + serviceIpcParse(&g_capssuSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && out) *out = resp->out; + } + + return rc; +} + +Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out) { + CapsScreenShotAttribute attr; + + memset(&attr, 0, sizeof(attr)); + attr.unk_x0 = attr_val; + + return _capssuSaveScreenShotEx0(buffer, size, &attr, unk, out); +} + +Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) { + return _capssuSaveScreenShotEx0(buffer, size, attr, unk, out); +} +