From eb078b295503f68c755a921b9d30b73b6a4997ab Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Fri, 24 Jan 2020 07:17:50 +0100 Subject: [PATCH 01/17] add caps:c --- nx/include/switch.h | 1 + nx/include/switch/services/caps.h | 5 + nx/include/switch/services/capsc.h | 51 +++++ nx/source/services/capsc.c | 314 +++++++++++++++++++++++++++++ 4 files changed, 371 insertions(+) create mode 100644 nx/include/switch/services/capsc.h create mode 100644 nx/source/services/capsc.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 81f14dcf..465d4262 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -93,6 +93,7 @@ extern "C" { #include "switch/services/psc.h" #include "switch/services/caps.h" #include "switch/services/capsa.h" +#include "switch/services/capsc.h" #include "switch/services/capsu.h" #include "switch/services/capssc.h" #include "switch/services/capssu.h" diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index 0aa966f1..f12c9d93 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -201,6 +201,11 @@ typedef struct { u8 unk_x8[8]; ///< Unknown } CapsAlbumCache; +/// AlbumCommitOutput +typedef struct { + u64 unk[4]; ///< Unknown. Official sw sets this to 0. +} CapsAlbumCommitOutput; + /// Gets the ShimLibraryVersion. u64 capsGetShimLibraryVersion(void); diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h new file mode 100644 index 00000000..bcc1753f --- /dev/null +++ b/nx/include/switch/services/capsc.h @@ -0,0 +1,51 @@ +/** + * @file capsc.h + * @brief Album Control (caps:c) service IPC wrapper. + * @author Behemoth + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../sf/service.h" +#include "../services/caps.h" + +/// Initialize caps:c +Result capscInitialize(void); + +/// Exit caps:c. +void capscExit(void); + +/// Gets the Service for caps:c. +Service* capscGetServiceSession(void); +Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); +Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); +Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); +Result capscCheckApplicationIdRegistered(u64 application_id); +Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id); +Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size); +Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size); + +Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id); +Result capscCloseAlbumMovieStream(u64 stream); +Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size); +Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); +Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream); +Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size); +Result capscReadImageDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); +Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute); +Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id); +Result capscFinishAlbumMovieWriteStream(u64 stream); +Result capscCommitAlbumMovieWriteStream(u64 stream); +Result capscDiscardAlbumMovieWriteStream(u64 stream); +Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream); +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out); +Result capscStartAlbumMovieWriteStreamDataSection(u64 stream); +Result capscEndAlbumMovieWriteStreamDataSection(u64 stream); +Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream); +Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream); +Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size); +Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); +Result capscWriteMetaToAlbumMovieWriteStream(); +Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream); +Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size); +Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c new file mode 100644 index 00000000..f9def1b8 --- /dev/null +++ b/nx/source/services/capsc.c @@ -0,0 +1,314 @@ +#define NX_SERVICE_ASSUME_NON_DOMAIN +#include +#include +#include "service_guard.h" +#include "runtime/hosversion.h" +#include "services/applet.h" +#include "services/capsc.h" + +static Service g_capscSrv; +static Service g_capscControl; + +NX_GENERATE_SERVICE_GUARD(capsc); + +Result _capscInitialize(void) { + return smGetService(&g_capscSrv, "caps:c"); +} + +void _capscCleanup(void) { + serviceClose(&g_capscControl); + serviceClose(&g_capscSrv); +} + +Service* capscGetServiceSession(void) { + return &g_capscSrv; +} + +static Result _capscCmdInU8NoOut(Service *srv, u32 cmd_id, u8 inval) { + return serviceDispatchIn(srv, cmd_id, inval); +} + +Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage) { + u8 inval = storage; + return _capscCmdInU8NoOut(&g_capscSrv, 1001, inval); +} + +Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage) { + u8 inval = storage; + return _capscCmdInU8NoOut(&g_capscSrv, 1002, inval); +} + +Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid) { + return serviceDispatchInOut(&g_capscSrv, 2013, aruid, *application_id); +} + +Result capscCheckApplicationIdRegistered(u64 application_id) { + return _capscCmdInU8NoOut(&g_capscSrv, 2014, application_id); +} + +Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id) { + const struct { + u8 type; + u64 application_id; + } in = { contents, application_id }; + return serviceDispatchInOut(&g_capscSrv, 2101, in, *file_id); +} + +Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size) { + if (hosversionAtLeast(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return serviceDispatchIn(&g_capscSrv, 2201, file_id, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, buffer_size }, }, + ); +} + +Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + CapsAlbumFileId file_id; + u64 unk_0; + u64 unk_1; + u64 unk_2; + } in = { *file_id, unk_0, unk_1, unk_2 }; + return serviceDispatchIn(&g_capscSrv, 2202, in, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, buffer_size }, }, + ); +} + +Result _capscSetOverlayThumbnailData(u32 cmd_id, CapsAlbumFileId *file_id, void* buffer, u64 size) { + return serviceDispatchIn(&g_capscSrv, cmd_id, *file_id, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size }, }, + ); +} + +Result capscSetOverlayScreenShotThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _capscSetOverlayThumbnailData(2301, file_id, buffer, size); +} + +Result capscSetOverlayMovieThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _capscSetOverlayThumbnailData(2302, file_id, buffer, size); +} + +static Result _capscOpenControlSession(Service *srv_out) { + u64 AppletResourceUserId = appletGetAppletResourceUserId(); + + return serviceDispatchIn(&g_capscSrv, 60001, AppletResourceUserId, + .in_send_pid = true, + .out_num_objects = 1, + .out_objects = srv_out, + ); +} + +Result _capscOpenAlbumMovieStream(u32 cmd_id, const CapsAlbumFileId *file_id, u64 *stream) { + return serviceDispatchInOut(&g_capscControl, cmd_id, *file_id, *stream); +} + +Result _capscControlReadDataFromAlbumMovieStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 offset; + } in = { stream, offset }; + + return serviceDispatchInOut(&g_capscControl, cmd_id, in, *actual_size, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { buffer, size } }, + ); +} + +Result _capscControlCmdInU8NoOut(u32 cmd_id, u8 inval) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchIn(&g_capscControl, cmd_id, inval); +} + +Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + + if (!serviceIsActive(&g_capscControl)) rc = _capscOpenControlSession(&g_capscControl); + + if (R_SUCCEEDED(rc)) rc = _capscOpenAlbumMovieStream(2001, file_id, stream); + + return rc; +} + +Result capscCloseAlbumMovieStream(u64 stream) { + return _capscControlCmdInU8NoOut(2002, stream); +} + +Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2003, stream, *size); +} + +Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2004, stream, offset, buffer, size, actual_size); +} + +Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream) { + return _capscControlCmdInU8NoOut(2005, stream); +} + +Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2006, stream, *size); +} + +Result capscReadImageDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2007, stream, offset, buffer, size, actual_size); +} + +Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2008, stream, *attribute); +} + +Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + + if (!serviceIsActive(&g_capscControl)) rc = _capscOpenControlSession(&g_capscControl); + + if (R_SUCCEEDED(rc)) rc = _capscOpenAlbumMovieStream(2401, file_id, stream); + + return rc; +} + +Result capscFinishAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2402, stream); +} + +Result capscCommitAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2403, stream); +} + +Result capscDiscardAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2404, stream); +} + +Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream) { + return _capscControlCmdInU8NoOut(2405, stream); +} + +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2008, stream, *out); +} + +Result capscStartAlbumMovieWriteStreamDataSection(u64 stream) { + return _capscControlCmdInU8NoOut(2411, stream); +} + +Result capscEndAlbumMovieWriteStreamDataSection(u64 stream) { + return _capscControlCmdInU8NoOut(2412, stream); +} + +Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream) { + return _capscControlCmdInU8NoOut(2413, stream); +} + +Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream) { + return _capscControlCmdInU8NoOut(2414, stream); +} + +Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2421, stream, offset, buffer, size, actual_size); +} + +Result _capscWriteToAlbumMovieWriteStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 offset; + } in = { stream, offset }; + return serviceDispatchIn(&g_capscControl, cmd_id, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size } }, + ); +} + +Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size) { + return _capscWriteToAlbumMovieWriteStream(2422, stream, offset, buffer, size); +} + +Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size) { + return _capscWriteToAlbumMovieWriteStream(2422, stream, offset, buffer, size); +} + +Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream) { + return _capscControlCmdInU8NoOut(2431, stream); +} + +Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2433, stream, *size); +} + +Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 size; + } in = { stream, size }; + return serviceDispatchIn(&g_capscControl, 2434, in); +} + + + From 8d27cc04ae604136c3d1d2d456866c35ef011314 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Sun, 26 Jan 2020 18:47:42 +0100 Subject: [PATCH 02/17] capsc, capsa: cleanup, add calls --- nx/include/switch/services/capsa.h | 19 ++++++- nx/include/switch/services/capsc.h | 2 + nx/source/services/capsa.c | 20 ++++++++ nx/source/services/capsc.c | 81 ++++++++++++++++++++---------- 4 files changed, 95 insertions(+), 27 deletions(-) diff --git a/nx/include/switch/services/capsa.h b/nx/include/switch/services/capsa.h index 7dce12b8..d789c397 100644 --- a/nx/include/switch/services/capsa.h +++ b/nx/include/switch/services/capsa.h @@ -116,6 +116,14 @@ Result capsaLoadAlbumScreenShotImage(u64 *width, u64 *height, const CapsAlbumFil */ Result capsaLoadAlbumScreenShotThumbnailImage(u64 *width, u64 *height, const CapsAlbumFileId *file_id, void* image, u64 image_size, void* workbuf, u64 workbuf_size); +/** + * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry + * @note Only available on [2.0.0+]. + * @param[out] entry \ref CapsAlbumEntry + * @param[in] application_entry \ref CapsApplicationAlbumEntry + */ +Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry); + /** * @brief Load the ScreenShotImage for the specified AlbumFile. * @note Only available on [3.0.0+]. @@ -305,6 +313,7 @@ Result capsaRefreshAlbumCache(CapsAlbumStorage storage); /** * @brief Gets the AlbumCache of the specified AlbumStorage. + * @note Stubbed on [4.0.0+]. * @note use \ref capsaGetAlbumCacheEx instead. * @param[in] storage \ref CapsAlbumStorage * @param[out] cache \ref CapsAlbumCache @@ -313,13 +322,21 @@ Result capsaGetAlbumCache(CapsAlbumStorage storage, CapsAlbumCache *cache); /** * @brief Gets the AlbumCache for the specified type of the specified AlbumStorage. - * @note Stubbed on [4.0.0+]. * @param[in] storage \ref CapsAlbumStorage * @param[in] contents \ref CapsAlbumFileContents * @param[out] cache \ref CapsAlbumCache */ Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents contents, CapsAlbumCache *cache); +/** + * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry + * @note Only available on [2.0.0+]. + * @note despite this having aruid in the name \ref capsaGetAlbumEntryFromApplicationAlbumEntry also sends it. + * @param[out] entry \ref CapsAlbumEntry + * @param[in] application_entry \ref CapsApplicationAlbumEntry + */ +Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry); + /** * @brief Opens an AlbumMovieStream. * @note This opens IAlbumAccessorSession if not previously opened, it's closed during \ref capsaExit. diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index bcc1753f..b61265a9 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -17,6 +17,8 @@ void capscExit(void); /// Gets the Service for caps:c. Service* capscGetServiceSession(void); +Result capscRegisterAppletResourceUserId(void); +Result capscUnregisterAppletResourceUserId(void); Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); diff --git a/nx/source/services/capsa.c b/nx/source/services/capsa.c index bf571a1c..c5c48ea8 100644 --- a/nx/source/services/capsa.c +++ b/nx/source/services/capsa.c @@ -112,6 +112,16 @@ Result capsaLoadAlbumScreenShotThumbnailImage(u64 *width, u64 *height, const Cap return _capsaLoadAlbumScreenshot(width, height, file_id, image, image_size, workbuf, workbuf_size, 10); } +Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + CapsApplicationAlbumEntry application_entry; + u64 aruid; + } in = { *application_entry, appletGetAppletResourceUserId() }; + return serviceDispatchInOut(&g_capsaSrv, 11, in, *entry); +} + static Result _capsaLoadAlbumScreenshotEx(u64 *width, u64 *height, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size, u32 cmd_id) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -322,6 +332,16 @@ Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents cont return serviceDispatchInOut(&g_capsaSrv, 8013, in, *cache); } +Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + CapsApplicationAlbumEntry application_entry; + u64 aruid; + } in = { *application_entry, appletGetAppletResourceUserId() }; + return serviceDispatchInOut(&g_capsaSrv, 8021, in, *entry, .in_send_pid = true); +} + static Result _capsaOpenAccessorSession(Service *srv_out) { u64 AppletResourceUserId = appletGetAppletResourceUserId(); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index f9def1b8..a84250c3 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -9,10 +9,18 @@ static Service g_capscSrv; static Service g_capscControl; +static Result _capscSetShimLibraryVersion(u64 version); + NX_GENERATE_SERVICE_GUARD(capsc); Result _capscInitialize(void) { - return smGetService(&g_capscSrv, "caps:c"); + Result rc=0; + + rc = smGetService(&g_capscSrv, "caps:c"); + + if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capscSetShimLibraryVersion(capsGetShimLibraryVersion()); + + return rc; } void _capscCleanup(void) { @@ -24,29 +32,66 @@ Service* capscGetServiceSession(void) { return &g_capscSrv; } -static Result _capscCmdInU8NoOut(Service *srv, u32 cmd_id, u8 inval) { +static Result _capscSetShimLibraryVersion(u64 version) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + u64 version; + u64 AppletResourceUserId; + } in = { version, appletGetAppletResourceUserId() }; + return serviceDispatchIn(&g_capscSrv, 33, in); +} + +static Result _capscCmdInU8NoOut(Service *srv, u32 cmd_id, u64 inval) { return serviceDispatchIn(srv, cmd_id, inval); } Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage) { u8 inval = storage; - return _capscCmdInU8NoOut(&g_capscSrv, 1001, inval); + return _capscCmdInU8NoOut(&g_capscSrv, 2001, inval); } Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage) { u8 inval = storage; - return _capscCmdInU8NoOut(&g_capscSrv, 1002, inval); + return _capscCmdInU8NoOut(&g_capscSrv, 2002, inval); +} + +Result capscRegisterAppletResourceUserId(void) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + u64 AppletResourceUserId; + u64 version; + } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; + return serviceDispatchIn(&g_capscSrv, 2011, in); +} + +Result capscUnregisterAppletResourceUserId(void) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + u64 AppletResourceUserId; + u64 version; + } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; + return serviceDispatchIn(&g_capscSrv, 2012, in); } Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return serviceDispatchInOut(&g_capscSrv, 2013, aruid, *application_id); } Result capscCheckApplicationIdRegistered(u64 application_id) { - return _capscCmdInU8NoOut(&g_capscSrv, 2014, application_id); + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchIn(&g_capscSrv, 2014, application_id); } Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { u8 type; u64 application_id; @@ -78,7 +123,7 @@ Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 u ); } -Result _capscSetOverlayThumbnailData(u32 cmd_id, CapsAlbumFileId *file_id, void* buffer, u64 size) { +static Result _capscSetOverlayThumbnailData(u32 cmd_id, CapsAlbumFileId *file_id, void* buffer, u64 size) { return serviceDispatchIn(&g_capscSrv, cmd_id, *file_id, .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { buffer, size }, }, @@ -99,7 +144,6 @@ Result capscSetOverlayMovieThumbnailData(CapsAlbumFileId *file_id, void* buffer, static Result _capscOpenControlSession(Service *srv_out) { u64 AppletResourceUserId = appletGetAppletResourceUserId(); - return serviceDispatchIn(&g_capscSrv, 60001, AppletResourceUserId, .in_send_pid = true, .out_num_objects = 1, @@ -107,48 +151,39 @@ static Result _capscOpenControlSession(Service *srv_out) { ); } -Result _capscOpenAlbumMovieStream(u32 cmd_id, const CapsAlbumFileId *file_id, u64 *stream) { +static Result _capscOpenAlbumMovieStream(u32 cmd_id, const CapsAlbumFileId *file_id, u64 *stream) { return serviceDispatchInOut(&g_capscControl, cmd_id, *file_id, *stream); } -Result _capscControlReadDataFromAlbumMovieStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { +static Result _capscControlReadDataFromAlbumMovieStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - const struct { u64 stream; u64 offset; } in = { stream, offset }; - return serviceDispatchInOut(&g_capscControl, cmd_id, in, *actual_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { buffer, size } }, ); } -Result _capscControlCmdInU8NoOut(u32 cmd_id, u8 inval) { +static Result _capscControlCmdInU8NoOut(u32 cmd_id, u8 inval) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - return serviceDispatchIn(&g_capscControl, cmd_id, inval); } Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - Result rc=0; - if (!serviceIsActive(&g_capscControl)) rc = _capscOpenControlSession(&g_capscControl); - if (R_SUCCEEDED(rc)) rc = _capscOpenAlbumMovieStream(2001, file_id, stream); - return rc; } @@ -159,10 +194,8 @@ Result capscCloseAlbumMovieStream(u64 stream) { Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - return serviceDispatchInOut(&g_capscControl, 2003, stream, *size); } @@ -177,10 +210,8 @@ Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream) { Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - return serviceDispatchInOut(&g_capscControl, 2006, stream, *size); } @@ -257,13 +288,11 @@ Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buff return _capscControlReadDataFromAlbumMovieStream(2421, stream, offset, buffer, size, actual_size); } -Result _capscWriteToAlbumMovieWriteStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, u64 size) { +static Result _capscWriteToAlbumMovieWriteStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, u64 size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - const struct { u64 stream; u64 offset; From c09396fdbacf35c09dc082fc5c85e1ced299ab16 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Sun, 26 Jan 2020 20:06:56 +0100 Subject: [PATCH 03/17] capsc: fix parameter name order --- nx/source/services/capsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index a84250c3..5422c2ae 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -60,8 +60,8 @@ Result capscRegisterAppletResourceUserId(void) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { - u64 AppletResourceUserId; u64 version; + u64 AppletResourceUserId; } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; return serviceDispatchIn(&g_capscSrv, 2011, in); } @@ -70,8 +70,8 @@ Result capscUnregisterAppletResourceUserId(void) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { - u64 AppletResourceUserId; u64 version; + u64 AppletResourceUserId; } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; return serviceDispatchIn(&g_capscSrv, 2012, in); } From aef568b2069f47d6bb6361f628659589b01a84cd Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Sun, 26 Jan 2020 20:08:02 +0100 Subject: [PATCH 04/17] capsa: fix capsaGetAlbumEntryFromApplicationAlbumEntry* --- nx/include/switch/services/capsa.h | 11 ++++++----- nx/source/services/capsa.c | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/nx/include/switch/services/capsa.h b/nx/include/switch/services/capsa.h index d789c397..0730775e 100644 --- a/nx/include/switch/services/capsa.h +++ b/nx/include/switch/services/capsa.h @@ -117,12 +117,13 @@ Result capsaLoadAlbumScreenShotImage(u64 *width, u64 *height, const CapsAlbumFil Result capsaLoadAlbumScreenShotThumbnailImage(u64 *width, u64 *height, const CapsAlbumFileId *file_id, void* image, u64 image_size, void* workbuf, u64 workbuf_size); /** - * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry + * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry and an Application Id. * @note Only available on [2.0.0+]. * @param[out] entry \ref CapsAlbumEntry * @param[in] application_entry \ref CapsApplicationAlbumEntry + * @param[in] application_id Application Id */ -Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry); +Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry, u64 application_id); /** * @brief Load the ScreenShotImage for the specified AlbumFile. @@ -329,13 +330,13 @@ Result capsaGetAlbumCache(CapsAlbumStorage storage, CapsAlbumCache *cache); Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents contents, CapsAlbumCache *cache); /** - * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry + * @brief Load an \ref CapsAlbumEntry from a \ref CapsApplicationAlbumEntry and an Applet Resource User Id. * @note Only available on [2.0.0+]. - * @note despite this having aruid in the name \ref capsaGetAlbumEntryFromApplicationAlbumEntry also sends it. * @param[out] entry \ref CapsAlbumEntry * @param[in] application_entry \ref CapsApplicationAlbumEntry + * @param[in] appletResourceUserId Application Resouce User Id */ -Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry); +Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry, u64 appletResourceUserId); /** * @brief Opens an AlbumMovieStream. diff --git a/nx/source/services/capsa.c b/nx/source/services/capsa.c index c5c48ea8..d37ede5f 100644 --- a/nx/source/services/capsa.c +++ b/nx/source/services/capsa.c @@ -112,13 +112,13 @@ Result capsaLoadAlbumScreenShotThumbnailImage(u64 *width, u64 *height, const Cap return _capsaLoadAlbumScreenshot(width, height, file_id, image, image_size, workbuf, workbuf_size, 10); } -Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry) { +Result capsaGetAlbumEntryFromApplicationAlbumEntry(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry, u64 application_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsApplicationAlbumEntry application_entry; - u64 aruid; - } in = { *application_entry, appletGetAppletResourceUserId() }; + u64 application_id; + } in = { *application_entry, application_id }; return serviceDispatchInOut(&g_capsaSrv, 11, in, *entry); } @@ -332,13 +332,13 @@ Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents cont return serviceDispatchInOut(&g_capsaSrv, 8013, in, *cache); } -Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry) { +Result capsaGetAlbumEntryFromApplicationAlbumEntryAruid(CapsAlbumEntry *entry, const CapsApplicationAlbumEntry *application_entry, u64 appletResourceUserId) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsApplicationAlbumEntry application_entry; u64 aruid; - } in = { *application_entry, appletGetAppletResourceUserId() }; + } in = { *application_entry, appletResourceUserId }; return serviceDispatchInOut(&g_capsaSrv, 8021, in, *entry, .in_send_pid = true); } From c29b43d476f1e805dd2a6b8989311c4379624c27 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Sun, 26 Jan 2020 22:43:38 +0100 Subject: [PATCH 05/17] cleanup --- nx/include/switch/services/capsc.h | 4 ++-- nx/source/services/capsc.c | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index b61265a9..6deb7195 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -17,10 +17,10 @@ void capscExit(void); /// Gets the Service for caps:c. Service* capscGetServiceSession(void); -Result capscRegisterAppletResourceUserId(void); -Result capscUnregisterAppletResourceUserId(void); Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); +Result capscRegisterAppletResourceUserId(u64 appletResourceUserId); +Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId); Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); Result capscCheckApplicationIdRegistered(u64 application_id); Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index 5422c2ae..3f3fb720 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -56,23 +56,23 @@ Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage) { return _capscCmdInU8NoOut(&g_capscSrv, 2002, inval); } -Result capscRegisterAppletResourceUserId(void) { +Result capscRegisterAppletResourceUserId(u64 appletResourceUserId) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { u64 version; u64 AppletResourceUserId; - } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; + } in = { capsGetShimLibraryVersion(), appletResourceUserId }; return serviceDispatchIn(&g_capscSrv, 2011, in); } -Result capscUnregisterAppletResourceUserId(void) { +Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { u64 version; u64 AppletResourceUserId; - } in = { capsGetShimLibraryVersion(), appletGetAppletResourceUserId() }; + } in = { capsGetShimLibraryVersion(), appletResourceUserId }; return serviceDispatchIn(&g_capscSrv, 2012, in); } @@ -100,7 +100,7 @@ Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents } Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size) { - if (hosversionAtLeast(4,0,0)) + if (hosversionBefore(2,0,0) || hosversionAtLeast(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return serviceDispatchIn(&g_capscSrv, 2201, file_id, .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, @@ -265,7 +265,7 @@ Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - return serviceDispatchInOut(&g_capscControl, 2008, stream, *out); + return serviceDispatchInOut(&g_capscControl, 2406, stream, *out); } Result capscStartAlbumMovieWriteStreamDataSection(u64 stream) { @@ -308,7 +308,7 @@ Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffe } Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size) { - return _capscWriteToAlbumMovieWriteStream(2422, stream, offset, buffer, size); + return _capscWriteToAlbumMovieWriteStream(2424, stream, offset, buffer, size); } Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream) { @@ -338,6 +338,3 @@ Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size) { } in = { stream, size }; return serviceDispatchIn(&g_capscControl, 2434, in); } - - - From 34af04498e8f50f707e358948d785b2a986e5351 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Mon, 27 Jan 2020 10:33:36 +0100 Subject: [PATCH 06/17] caps: fix incompatible calls --- nx/include/switch/services/capsa.h | 3 ++- nx/include/switch/services/capsc.h | 2 +- nx/source/services/capsa.c | 19 ++++++++++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/nx/include/switch/services/capsa.h b/nx/include/switch/services/capsa.h index 0730775e..219d6e2d 100644 --- a/nx/include/switch/services/capsa.h +++ b/nx/include/switch/services/capsa.h @@ -187,9 +187,10 @@ Result capsaGetAlbumMountResult(CapsAlbumStorage storage); * @brief Returns the AlbumUsage for a specified \ref CapsAlbumStorage. * @note Only available on [4.0.0+]. * @param[in] storage \ref CapsAlbumStorage + * @param[in] flags \ref CapsAlbumFileContentsFlag * @param[out] out \ref CapsAlbumUsage16 */ -Result capsaGetAlbumUsage16(CapsAlbumStorage storage, CapsAlbumUsage16 *out); +Result capsaGetAlbumUsage16(CapsAlbumStorage storage, u8 flags, CapsAlbumUsage16 *out); /** * @brief Returns the start and end of the Applet Id range. diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index 6deb7195..eb822aab 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -47,7 +47,7 @@ Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream); Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream); Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size); Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); -Result capscWriteMetaToAlbumMovieWriteStream(); +Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream); Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size); Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size); diff --git a/nx/source/services/capsa.c b/nx/source/services/capsa.c index d37ede5f..5e56ebf0 100644 --- a/nx/source/services/capsa.c +++ b/nx/source/services/capsa.c @@ -193,11 +193,19 @@ Result capsaGetAlbumMountResult(CapsAlbumStorage storage) { return _capsaCmdInU8NoOut(&g_capsaSrv, storage, 16); } -Result capsaGetAlbumUsage16(CapsAlbumStorage storage, CapsAlbumUsage16 *out) { +Result capsaGetAlbumUsage16(CapsAlbumStorage storage, u8 flags, CapsAlbumUsage16 *out) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - u8 inval = storage; - return serviceDispatchInOut(&g_capsaSrv, 17, inval, *out); + struct { + u8 storage; + u8 pad_x1[7]; + u8 flags; + u8 pad_x9[7]; + } in = { storage, {0}, flags, {0} }; + return serviceDispatchIn(&g_capsaSrv, 17, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_FixedSize, }, + .buffers = { { out, sizeof(CapsAlbumUsage16) } }, + ); } Result capsaGetMinMaxAppletId(bool *success, u64* min, u64* max) { @@ -238,7 +246,7 @@ Result capsaGetAlbumFileListEx0(CapsAlbumStorage storage, u8 flags, u64 *out, Ca struct { u8 storage; u8 pad_x1[7]; - u8 contents; + u8 flags; u8 pad_x9[7]; } in = { storage, {0}, flags, {0} }; return serviceDispatchInOut(&g_capsaSrv, 101, in, *out, @@ -319,7 +327,8 @@ Result capsaRefreshAlbumCache(CapsAlbumStorage storage) { } Result capsaGetAlbumCache(CapsAlbumStorage storage, CapsAlbumCache *cache) { - return serviceDispatchInOut(&g_capsaSrv, 8012, storage, *cache); + u8 inval = storage; + return serviceDispatchInOut(&g_capsaSrv, 8012, inval, *cache); } Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents contents, CapsAlbumCache *cache) { From 399dd40b89df4ff883eee9a5334a946c99f2ded9 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Wed, 29 Jan 2020 06:52:03 +0100 Subject: [PATCH 07/17] fix cache unk type --- nx/include/switch/services/caps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index f12c9d93..29dc936a 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -198,7 +198,7 @@ typedef enum { /// AlbumCache typedef struct { u64 count; ///< Count - u8 unk_x8[8]; ///< Unknown + u64 unk_x8; ///< Unknown } CapsAlbumCache; /// AlbumCommitOutput From 420bc60d72d9c147ffd0af5b6cc7402f2f7d47e7 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Mon, 10 Feb 2020 18:36:57 +0100 Subject: [PATCH 08/17] fix structs expose overlay fix aruid un-/registration --- nx/include/switch/services/caps.h | 14 +++++----- nx/include/switch/services/capsc.h | 7 +++-- nx/source/services/capsc.c | 41 ++++++++++++++++++------------ 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index a52ca0f5..67d5341e 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -88,9 +88,8 @@ typedef struct { CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime u8 storage; ///< \ref CapsAlbumStorage u8 content; ///< \ref CapsAlbumFileContents - u32 pad_x12; ///< Set to 0 by official software - u16 pad_x16; ///< Set to 0 by official software -} PACKED CapsAlbumFileId; + u8 pad_x12[0x6]; ///< padding +} CapsAlbumFileId; /// AlbumEntry typedef struct { @@ -104,14 +103,17 @@ typedef struct { u8 data[0x20]; ///< Data. struct { - u8 unk_x0[0x20]; ///< Unknown. + u8 unk_x0[0x20]; ///< aes256 with random key over \ref AlbumEntry. } v0; ///< Pre-7.0.0 struct { u64 size; ///< size of the entry - u64 application_id; ///< ApplicationId + u64 hash; ///< aes256 with hardcoded key over \ref AlbumEntry. CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime - u8 unk_x18[0x8]; ///< Unknown. + u8 storage; ///< \ref CapsAlbumStorage + u8 content; ///< \ref CapsAlbumFileContents + u8 pad_x1a[0x5]; ///< padding + u8 unk_x1f; ///< Set to 1 by official software } v1; ///< [7.0.0+] }; } CapsApplicationAlbumEntry; diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index eb822aab..86524397 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -19,13 +19,16 @@ void capscExit(void); Service* capscGetServiceSession(void); Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); -Result capscRegisterAppletResourceUserId(u64 appletResourceUserId); -Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId); +Result capscRegisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id); +Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id); Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); Result capscCheckApplicationIdRegistered(u64 application_id); Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id); +Result capscGenerateApplicationAlbumEntry(CapsApplicationAlbumEntry *appEntry, const CapsAlbumEntry *entry, u64 application_id); Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size); Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size); +Result capscSetOverlayScreenShotThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size); +Result capscSetOverlayMovieThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size); Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id); Result capscCloseAlbumMovieStream(u64 stream); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index 3f3fb720..5cb82068 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -56,23 +56,23 @@ Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage) { return _capscCmdInU8NoOut(&g_capscSrv, 2002, inval); } -Result capscRegisterAppletResourceUserId(u64 appletResourceUserId) { +Result capscRegisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { - u64 version; - u64 AppletResourceUserId; - } in = { capsGetShimLibraryVersion(), appletResourceUserId }; + u64 appletResourceUserId; + u64 applicationId; + } in = { appletResourceUserId, application_id }; return serviceDispatchIn(&g_capscSrv, 2011, in); } -Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId) { +Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { - u64 version; - u64 AppletResourceUserId; - } in = { capsGetShimLibraryVersion(), appletResourceUserId }; + u64 appletResourceUserId; + u64 applicationId; + } in = { appletResourceUserId, application_id }; return serviceDispatchIn(&g_capscSrv, 2012, in); } @@ -85,7 +85,6 @@ Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid) { Result capscCheckApplicationIdRegistered(u64 application_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return serviceDispatchIn(&g_capscSrv, 2014, application_id); } @@ -94,11 +93,21 @@ Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { u8 type; - u64 application_id; + u64 applicationId; } in = { contents, application_id }; return serviceDispatchInOut(&g_capscSrv, 2101, in, *file_id); } +Result capscGenerateApplicationAlbumEntry(CapsApplicationAlbumEntry *appEntry, const CapsAlbumEntry *entry, u64 application_id) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + CapsAlbumEntry entry; + u64 applicationId; + } in = { *entry, application_id }; + return serviceDispatchInOut(&g_capscSrv, 2102, in, *appEntry); +} + Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size) { if (hosversionBefore(2,0,0) || hosversionAtLeast(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -123,23 +132,23 @@ Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 u ); } -static Result _capscSetOverlayThumbnailData(u32 cmd_id, CapsAlbumFileId *file_id, void* buffer, u64 size) { +static Result _capscSetOverlayThumbnailData(u32 cmd_id, const CapsAlbumFileId *file_id, const void* image, u64 image_size) { return serviceDispatchIn(&g_capscSrv, cmd_id, *file_id, .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, - .buffers = { { buffer, size }, }, + .buffers = { { image, image_size }, }, ); } -Result capscSetOverlayScreenShotThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { +Result capscSetOverlayScreenShotThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _capscSetOverlayThumbnailData(2301, file_id, buffer, size); + return _capscSetOverlayThumbnailData(2301, file_id, image, image_size); } -Result capscSetOverlayMovieThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { +Result capscSetOverlayMovieThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _capscSetOverlayThumbnailData(2302, file_id, buffer, size); + return _capscSetOverlayThumbnailData(2302, file_id, image, image_size); } static Result _capscOpenControlSession(Service *srv_out) { From 44623257a3f4df34e19adb9fd91e40b8e9eb9c58 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Wed, 12 Feb 2020 17:10:24 +0100 Subject: [PATCH 09/17] add caps:c documentation --- nx/include/switch/services/capsc.h | 168 ++++++++++++++++++++++++++++- nx/source/services/capsc.c | 12 +-- 2 files changed, 172 insertions(+), 8 deletions(-) diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index 86524397..2f2032ff 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -17,27 +17,191 @@ void capscExit(void); /// Gets the Service for caps:c. Service* capscGetServiceSession(void); + +/** + * @brief Notify the service that a storage is now available. + * @note This will result in capsrv mounting the image directory on that storage medium. + * @param[in] storage \ref CapsAlbumStorage + */ Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); + +/** + * @brief Notify the service that a storage is now unavailable. + * @note This will result in capsrv unmounting the image directory on that storage medium. + * @param[in] storage \ref CapsAlbumStorage + */ Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); + +/** + * @brief Register an applet for later usage. + * @note Called at application launch. + * @note Will generate a random AES-256 key for this application for use on Shim-Version 0. + * @param[in] appletResourceUserId Session unique applet identifier. + * @param[in] application_id Title unique identifier. + */ Result capscRegisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id); + +/** + * @brief Unregister an applet. + * @note Called at application exit. + * @param[in] appletResourceUserId Session unique applet identifier. + * @param[in] application_id Title unique identifier. + */ Result capscUnregisterAppletResourceUserId(u64 appletResourceUserId, u64 application_id); + +/** + * @brief Get an Application ID that corresponse to an Application Resource User ID. + * @note Returns value set by \ref capscRegisterAppletResourceUserId. + * @param[out] application_id Title unique identifier. + * @param[in] appletResourceUserId Session unique applet identifier. + */ Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); + +/** + * @brief Checks whether an Application ID is registered. + * @param[in] application_id Title unique identifier. + */ Result capscCheckApplicationIdRegistered(u64 application_id); + +/** + * @brief Generate an Album File ID based of parameters and current time. + * @param[in] application_id Title unique identifier. + * @param[in] contents \ref CapsAlbumFileContents + * @param[out] file_id \ref CapsAlbumFileId + */ Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id); + +/** + * @brief Generate an Application Album Entry based of parameters. + * @note Output will be different between Shim Version 0 and 1. + * @param[out] appEntry \ref CapsApplicationAlbumEntry + * @param[in] entry \ref CapsAlbumEntry + * @param[in] application_id Title unique identifier. + */ Result capscGenerateApplicationAlbumEntry(CapsApplicationAlbumEntry *appEntry, const CapsAlbumEntry *entry, u64 application_id); -Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size); -Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size); + +/** + * @brief Save a jpeg image. + * @note Only available on [2.0.0-3.0.2]. + * @param[in] file_id \ref CapsAlbumFileId + * @param[in] buffer JPEG image buffer. + * @param[in] buffer_size Size of the JPEG image. + */ +Result capscSaveAlbumScreenShotFile(const CapsAlbumFileId *file_id, const void* buffer, u64 buffer_size); + +/** + * @brief Save a jpeg image. + * @note Only available on [4.0.0+]. + * @note Version 3 as of [9.1.0]. + * @param[in] file_id \ref CapsAlbumFileId + * @param[in] version Revision number. + * @param[in] makernote_offset Offset to makernote in JPEG buffer. + * @param[in] makernote_size Size of the makernote in JPEG buffer. + * @param[in] buffer JPEG image buffer. + * @param[in] buffer_size Size of the JPEG image. + */ +Result capscSaveAlbumScreenShotFileEx(const CapsAlbumFileId *file_id, u64 version, u64 makernote_offset, u64 makernote_size, const void* buffer, u64 buffer_size); + +/** + * @brief Sets thumbnail data for the last taken screenshot. + * @note 96×54x4 Image will get saved. + * @param[in] file_id \ref CapsAlbumFileId + * @param[in] image RGBA8 image buffer. + * @param[in] image_size size of the RGBA8 image buffer. + */ Result capscSetOverlayScreenShotThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size); + +/** + * @brief Sets thumbnail data for the last recorded movie. + * @note Only availabe on [4.0.0+]. + * @note 96×54x4 Image will get saved. + * @param[in] file_id \ref CapsAlbumFileId + * @param[in] image RGBA8 image buffer. + * @param[in] image_size size of the RGBA8 image buffer. + */ Result capscSetOverlayMovieThumbnailData(const CapsAlbumFileId *file_id, const void* image, u64 image_size); +/** + * @brief Opens an AlbumMovieReadStream. + * @note This opens IAlbumControlSession if not previously opened, it's closed during \ref capsaExit. + * @note Up to 4 streams can be open at the same time. Multiple streams can be open at the same time for the same \ref CapsAlbumFileId. + * @note Only available on [4.0.0+]. + * @param[out] stream Stream handle. + * @param[in] entry \ref CapsAlbumFileId + */ Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id); + +/** + * @brief Closes an AlbumMovieReadStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscCloseAlbumMovieStream(u64 stream); + +/** + * @brief Gets the data size of an AlbumMovieReadStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] size Size of the actual MP4, without the JPEG at the end. + */ Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size); + +/** + * @brief Reads data from an AlbumMovieReadStream. + * @note offset(+size) must not be negative. offset and size must be aligned to 0x40000-bytes. + * @note When offset(+size) goes beyond the size from \ref capsaGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[in] offset Offset. + * @param[out] Output data buffer. + * @param[in] size Data buffer size. + * @param[out] actual_size Actual read size. + */ Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); + +/** + * @brief Gets the BrokenReason for an AlbumMovieReadStream. + * @note Official sw doesn't use this. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream); + +/** + * @brief Gets the data size of an Image taken from an AlbumMovieReadStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] size Expected size of an Image. + */ Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size); + +/** + * @brief Reads data of an Image taken from an AlbumMovieReadStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[in] offset Offset. + * @param[out] Output data buffer. + * @param[in] size Data buffer size. + * @param[out] actual_size Actual read size. + */ Result capscReadImageDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); + +/** + * @brief Gets the file attribute of an AlbumMovieReadStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] attr \ref CapsScreenShotAttribute + */ Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute); + +/** + * @brief Opens an AlbumMovieWriteStream. + * @note This opens IAlbumControlSession if not previously opened, it's closed during \ref capsaExit. + * @note Up to 2 streams can be open at the same time. + * @note Only available on [4.0.0+]. + * @param[out] stream Stream handle. + * @param[in] entry \ref CapsAlbumFileId + */ Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id); Result capscFinishAlbumMovieWriteStream(u64 stream); Result capscCommitAlbumMovieWriteStream(u64 stream); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index 5cb82068..ce64e927 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -108,7 +108,7 @@ Result capscGenerateApplicationAlbumEntry(CapsApplicationAlbumEntry *appEntry, c return serviceDispatchInOut(&g_capscSrv, 2102, in, *appEntry); } -Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size) { +Result capscSaveAlbumScreenShotFile(const CapsAlbumFileId *file_id, const void* buffer, u64 buffer_size) { if (hosversionBefore(2,0,0) || hosversionAtLeast(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return serviceDispatchIn(&g_capscSrv, 2201, file_id, @@ -117,15 +117,15 @@ Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 ); } -Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size) { +Result capscSaveAlbumScreenShotFileEx(const CapsAlbumFileId *file_id, u64 version, u64 makernote_offset, u64 makernote_size, const void* buffer, u64 buffer_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsAlbumFileId file_id; - u64 unk_0; - u64 unk_1; - u64 unk_2; - } in = { *file_id, unk_0, unk_1, unk_2 }; + u64 version; + u64 mn_offset; + u64 mn_size; + } in = { *file_id, version, makernote_offset, makernote_size }; return serviceDispatchIn(&g_capscSrv, 2202, in, .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { buffer, buffer_size }, }, From 60e25ab49af723a1511fc68cf44a8f14edb045e2 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Wed, 12 Feb 2020 18:59:37 +0100 Subject: [PATCH 10/17] caps:a remove OverlayThumbnailData --- nx/include/switch/services/caps.h | 6 ------ nx/include/switch/services/capsa.h | 10 ++++++---- nx/source/services/capsa.c | 21 +++++++++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index 67d5341e..da2ad48a 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -164,12 +164,6 @@ typedef struct { CapsAlbumContentsUsage usages[16]; ///< \ref CapsAlbumContentsUsage } CapsAlbumUsage16; -/// OverlayThumbnailData -typedef struct { - CapsAlbumFileId file_id; ///< \ref CapsAlbumFileId - u64 size; ///< Size. -} CapsOverlayThumbnailData; - /// UserIdList typedef struct { AccountUid uids[ACC_USER_LIST_SIZE]; ///< \ref AccountUid diff --git a/nx/include/switch/services/capsa.h b/nx/include/switch/services/capsa.h index 219d6e2d..d341dd2d 100644 --- a/nx/include/switch/services/capsa.h +++ b/nx/include/switch/services/capsa.h @@ -223,20 +223,22 @@ Result capsaGetAlbumFileListEx0(CapsAlbumStorage storage, u8 flags, u64 *out, Ca /** * @brief Returns the image from the last shown ScreenShot Overlay. - * @param[out] data \ref CapsOverlayThumbnailData + * @param[out] file_id \ref CapsAlbumFileId + * @param[out] out_size Size of the thumbnail image. Always 0x5100. * @param[out] image RGBA8 image output buffer. * @param[in] image_size Image buffer size, should be at least large enough for RGBA8 96×54. */ -Result capsaGetLastOverlayScreenShotThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size); +Result capsaGetLastOverlayScreenShotThumbnail(CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size); /** * @brief Returns the image from the last shown Movie Overlay. * @note Only available on [4.0.0+]. - * @param[out] data \ref CapsOverlayThumbnailData + * @param[out] file_id \ref CapsAlbumFileId + * @param[out] out_size Size of the thumbnail image. Always 0x5100. * @param[out] image RGBA8 image output buffer. * @param[in] image_size Image buffer size, should be at least large enough for RGBA8 96×54. */ -Result capsaGetLastOverlayMovieThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size); +Result capsaGetLastOverlayMovieThumbnail(CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size); /** * @brief Gets the currently set autosaving storage. diff --git a/nx/source/services/capsa.c b/nx/source/services/capsa.c index 5e56ebf0..a7e50abf 100644 --- a/nx/source/services/capsa.c +++ b/nx/source/services/capsa.c @@ -255,21 +255,30 @@ Result capsaGetAlbumFileListEx0(CapsAlbumStorage storage, u8 flags, u64 *out, Ca ); } -Result _capsaGetLastOverlayThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size, u32 cmd_id) { - return serviceDispatchOut(&g_capsaSrv, cmd_id, *data, +Result _capsaGetLastOverlayThumbnail(CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size, u32 cmd_id) { + struct { + CapsAlbumFileId file_id; + u64 size; + } out; + Result rc = serviceDispatchOut(&g_capsaSrv, cmd_id, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, }, .buffers = { { image, image_size }, }, ); + if (R_SUCCEEDED(rc)) { + if (file_id) *file_id = out.file_id; + if (out_size) *out_size = out.size; + } + return rc; } -Result capsaGetLastOverlayScreenShotThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size) { - return _capsaGetLastOverlayThumbnail(data, image, image_size, 301); +Result capsaGetLastOverlayScreenShotThumbnail(CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size) { + return _capsaGetLastOverlayThumbnail(file_id, out_size, image, image_size, 301); } -Result capsaGetLastOverlayMovieThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size) { +Result capsaGetLastOverlayMovieThumbnail(CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _capsaGetLastOverlayThumbnail(data, image, image_size, 302); + return _capsaGetLastOverlayThumbnail(file_id, out_size, image, image_size, 302); } Result capsaGetAutoSavingStorage(CapsAlbumStorage *storage) { From 9bf745524d3198e74f8bdc8e9aba389a91b2ff6c Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 15 Feb 2020 12:32:50 -0500 Subject: [PATCH 11/17] nifm: Added NifmClientId and nifmGetClientId/nifmIsAnyInternetRequestAccepted. --- nx/include/switch/services/nifm.h | 17 +++++++++++++++++ nx/source/services/nifm.c | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/nx/include/switch/services/nifm.h b/nx/include/switch/services/nifm.h index 04d0cc7a..04956209 100644 --- a/nx/include/switch/services/nifm.h +++ b/nx/include/switch/services/nifm.h @@ -28,6 +28,11 @@ typedef enum { NifmInternetConnectionStatus_Connected = 4, ///< Internet is connected. } NifmInternetConnectionStatus; +/// ClientId +typedef struct { + u32 id; ///< ClientId +} NifmClientId; + /// Initialize nifm. This is used automatically by gethostid(). Result nifmInitialize(NifmServiceType service_type); @@ -40,6 +45,11 @@ Service* nifmGetServiceSession_StaticService(void); /// Gets the Service object for IGeneralService. Service* nifmGetServiceSession_GeneralService(void); +/** + * @brief GetClientId + */ +NifmClientId nifmGetClientId(void); + Result nifmGetCurrentIpAddress(u32* out); /** @@ -56,6 +66,13 @@ Result nifmIsWirelessCommunicationEnabled(bool* out); Result nifmGetInternetConnectionStatus(NifmInternetConnectionType* connectionType, u32* wifiStrength, NifmInternetConnectionStatus* connectionStatus); Result nifmIsEthernetCommunicationEnabled(bool* out); + +/** + * @brief IsAnyInternetRequestAccepted + * @param[in] id \ref NifmClientId + */ +bool nifmIsAnyInternetRequestAccepted(NifmClientId id); + Result nifmIsAnyForegroundRequestAccepted(bool* out); Result nifmPutToSleep(void); Result nifmWakeUp(void); diff --git a/nx/source/services/nifm.c b/nx/source/services/nifm.c index d03cbbf0..fcb63e20 100644 --- a/nx/source/services/nifm.c +++ b/nx/source/services/nifm.c @@ -105,6 +105,16 @@ static Result _nifmCreateGeneralService(Service* srv_out) { ); } +NifmClientId nifmGetClientId(void) { + NifmClientId id={0}; + Result rc = serviceDispatch(&g_nifmIGS, 1, + .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, + .buffers = { { &id, sizeof(id) } }, + ); + if (R_FAILED(rc)) id.id = 0; + return id; +} + Result nifmGetCurrentIpAddress(u32* out) { return _nifmCmdNoInOutU32(&g_nifmIGS, out, 12); } @@ -141,6 +151,15 @@ Result nifmIsEthernetCommunicationEnabled(bool* out) { return _nifmCmdNoInOutBool(&g_nifmIGS, out, 20); } +bool nifmIsAnyInternetRequestAccepted(NifmClientId id) { + u8 tmp=0; + Result rc = serviceDispatchOut(&g_nifmIGS, 21, tmp, + .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In }, + .buffers = { { &id, sizeof(id) } }, + ); + return R_SUCCEEDED(rc) ? tmp & 1 : 0; +} + Result nifmIsAnyForegroundRequestAccepted(bool* out) { return _nifmCmdNoInOutBool(&g_nifmIGS, out, 22); } From d8d931fe2558293a8e31b247a7cde49298dbd51e Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sun, 16 Feb 2020 21:32:56 -0500 Subject: [PATCH 12/17] ns: Added support for the following cmds: nsRequestApplicationUpdateInfo, nsRequestUpdateApplication2, nsRequestDownloadApplicationControlData, nsRequestCheckGameCardRegistration, nsRequestGameCardRegistrationGoldPoint, nsRequestRegisterGameCard, nsRequestDownloadApplicationPrepurchasedRights, nsRequestNoDownloadRightsErrorResolution, nsRequestResolveNoDownloadRightsError. --- nx/include/switch/services/ns.h | 82 +++++++++++++++++ nx/source/services/ns.c | 157 ++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index fbda2982..12559a82 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -209,6 +209,14 @@ Result nsIsApplicationEntityMovable(u64 application_id, NcmStorageId storage_id, */ Result nsMoveApplicationEntity(u64 application_id, NcmStorageId storage_id); +/** + * @brief RequestApplicationUpdateInfo + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @param[out] a \ref AsyncValue. The data that can be read from this is u8 ApplicationUpdateInfo. qlaunch just checks whether this is 0. + * @param application_id ApplicationId. + */ +Result nsRequestApplicationUpdateInfo(AsyncValue *a, u64 application_id); + /** * @brief CancelApplicationDownload * @param[in] application_id ApplicationId. @@ -343,6 +351,15 @@ Result nsResumeAll(void); */ Result nsGetStorageSize(NcmStorageId storage_id, s64 *total_space_size, s64 *free_space_size); +/** + * @brief RequestUpdateApplication2 + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [4.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] application_id ApplicationId. + */ +Result nsRequestUpdateApplication2(AsyncResult *a, u64 application_id); + /** * @brief DeleteUserSystemSaveData * @param[in] uid \ref AccountUid @@ -381,6 +398,44 @@ Result nsUnregisterNetworkServiceAccountWithUserSaveDataDeletion(AccountUid uid) */ Result nsGetApplicationControlData(NsApplicationControlSource source, u64 application_id, NsApplicationControlData* buffer, size_t size, u64* actual_size); +/** + * @brief RequestDownloadApplicationControlData + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @param[out] a \ref AsyncResult + * @param[in] application_id ApplicationId. + */ +Result nsRequestDownloadApplicationControlData(AsyncResult *a, u64 application_id); + +/** + * @brief RequestCheckGameCardRegistration + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [2.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] application_id ApplicationId. + */ +Result nsRequestCheckGameCardRegistration(AsyncResult *a, u64 application_id); + +/** + * @brief RequestGameCardRegistrationGoldPoint + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [2.0.0+]. + * @param[out] a \ref AsyncValue. The data that can be read from this is 4-bytes. + * @param[in] uid \ref AccountUid + * @param[in] application_id ApplicationId. + */ +Result nsRequestGameCardRegistrationGoldPoint(AsyncValue *a, AccountUid uid, u64 application_id); + +/** + * @brief RequestRegisterGameCard + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [2.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] uid \ref AccountUid + * @param[in] application_id ApplicationId. + * @param[in] inval Input value. + */ +Result nsRequestRegisterGameCard(AsyncResult *a, AccountUid uid, u64 application_id, s32 inval); + /** * @brief GetGameCardMountFailureEvent * @note The Event must be closed by the user once finished with it. @@ -486,6 +541,15 @@ Result nsNeedsSystemUpdateToFormatSdCard(bool *out); */ Result nsGetLastSdCardFormatUnexpectedResult(void); +/** + * @brief RequestDownloadApplicationPrepurchasedRights + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [4.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] application_id ApplicationId. + */ +Result nsRequestDownloadApplicationPrepurchasedRights(AsyncResult *a, u64 application_id); + /** * @brief Generates a \ref NsSystemDeliveryInfo using the currently installed SystemUpdate meta. * @note Only available on [4.0.0+]. @@ -673,6 +737,24 @@ Result nsGetApplicationDeliveryInfoHash(const NsApplicationDeliveryInfo *info, s */ Result nsGetApplicationTerminateResult(u64 application_id, Result *res); +/** + * @brief RequestNoDownloadRightsErrorResolution + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [9.0.0+]. + * @param[out] a \ref AsyncValue. The data that can be read from this is u8 NoDownloadRightsErrorResolution. + * @param application_id ApplicationId. + */ +Result nsRequestNoDownloadRightsErrorResolution(AsyncValue *a, u64 application_id); + +/** + * @brief RequestResolveNoDownloadRightsError + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [9.0.0+]. + * @param[out] a \ref AsyncValue. The data that can be read from this is u8 NoDownloadRightsErrorResolution. + * @param application_id ApplicationId. + */ +Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id); + ///@} ///@name IRequestServerStopper diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index be77ac0b..3fa3b530 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -4,6 +4,7 @@ #include "runtime/hosversion.h" #include "services/ns.h" #include "services/async.h" +#include "services/nifm.h" static Service g_nsAppManSrv, g_nsGetterSrv; static Service g_nsvmSrv; @@ -197,6 +198,42 @@ static Result _nsCmdNoInOutAsyncResult(Service* srv, AsyncResult *a, u32 cmd_id) return rc; } +static Result _nsCmdInU64OutAsyncValue(Service* srv, AsyncValue *a, u64 inval, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatchIn(srv, cmd_id, inval, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +static Result _nsCmdInU64OutAsyncResult(Service* srv, AsyncResult *a, u64 inval, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatchIn(srv, cmd_id, inval, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +static Result _nsCheckNifm(void) { + return nifmIsAnyInternetRequestAccepted(nifmGetClientId()) ? 0 : MAKERESULT(16, 340); +} + Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entry_offset, s32* out_entrycount) { return serviceDispatchInOut(&g_nsAppManSrv, 0, entry_offset, *out_entrycount, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, @@ -237,6 +274,13 @@ Result nsMoveApplicationEntity(u64 application_id, NcmStorageId storage_id) { return _nsCmdInU8U64NoOut(&g_nsAppManSrv, storage_id, application_id, 9); } +Result nsRequestApplicationUpdateInfo(AsyncValue *a, u64 application_id) { + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncValue(&g_nsAppManSrv, a, application_id, 30); +} + Result nsCancelApplicationDownload(u64 application_id) { return _nsCmdInU64(&g_nsAppManSrv, application_id, 32); } @@ -352,6 +396,16 @@ Result nsGetStorageSize(NcmStorageId storage_id, s64 *total_space_size, s64 *fre return rc; } +Result nsRequestUpdateApplication2(AsyncResult *a, u64 application_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncResult(&g_nsAppManSrv, a, application_id, 85); +} + Result nsDeleteUserSystemSaveData(AccountUid uid, u64 system_save_data_id) { const struct { AccountUid uid; @@ -396,6 +450,79 @@ Result nsGetApplicationControlData(NsApplicationControlSource source, u64 applic return rc; } +Result nsRequestDownloadApplicationControlData(AsyncResult *a, u64 application_id) { + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncResult(&g_nsAppManSrv, a, application_id, 402); +} + +Result nsRequestCheckGameCardRegistration(AsyncResult *a, u64 application_id) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncResult(&g_nsAppManSrv, a, application_id, 502); +} + +Result nsRequestGameCardRegistrationGoldPoint(AsyncValue *a, AccountUid uid, u64 application_id) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + const struct { + AccountUid uid; + u64 application_id; + } in = { uid, application_id }; + + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + rc = serviceDispatchIn(&g_nsAppManSrv, 503, in, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +Result nsRequestRegisterGameCard(AsyncResult *a, AccountUid uid, u64 application_id, s32 inval) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + const struct { + s32 inval; + u32 pad; + AccountUid uid; + u64 application_id; + } in = { inval, 0, uid, application_id }; + + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + rc = serviceDispatchIn(&g_nsAppManSrv, 504, in, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + Result nsGetGameCardMountFailureEvent(Event* out_event) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -525,6 +652,16 @@ Result nsGetLastSdCardFormatUnexpectedResult(void) { return _nsCmdNoIO(&g_nsAppManSrv, 1502); } +Result nsRequestDownloadApplicationPrepurchasedRights(AsyncResult *a, u64 application_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncResult(&g_nsAppManSrv, a, application_id, 1901); +} + Result nsGetSystemDeliveryInfo(NsSystemDeliveryInfo *info) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -803,6 +940,26 @@ Result nsGetApplicationTerminateResult(u64 application_id, Result *res) { return serviceDispatchInOut(&g_nsAppManSrv, 2100, application_id, *res); } +Result nsRequestNoDownloadRightsErrorResolution(AsyncValue *a, u64 application_id) { + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncValue(&g_nsAppManSrv, a, application_id, 2351); +} + +Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id) { + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + return _nsCmdInU64OutAsyncValue(&g_nsAppManSrv, a, application_id, 2352); +} + // IRequestServerStopper void nsRequestServerStopperClose(NsRequestServerStopper *r) { From c570cd0a2fdca092eca1796820afffa65b86c92e Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 17 Feb 2020 15:46:02 -0500 Subject: [PATCH 13/17] ns: Added NsApplicationRightsOnClient/nsGetApplicationRightsOnClient(). --- nx/include/switch/services/ns.h | 21 +++++++++++++++++++++ nx/source/services/ns.c | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index 12559a82..77c879b8 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -143,6 +143,15 @@ typedef struct { u8 hmac[0x20]; ///< HMAC-SHA256 over the above data. } NsApplicationDeliveryInfo; +/// NsApplicationRightsOnClient +typedef struct { + u64 application_id; ///< ApplicationId. + AccountUid uid; ///< \ref AccountUid + u8 flags_x18; ///< qlaunch uses bit0-bit4 and bit7 from here. + u8 flags_x19; ///< qlaunch uses bit0 from here. + u8 unk_x1a[0x6]; ///< Unknown. +} NsApplicationRightsOnClient; + /// Default size for \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater. This is the size used by qlaunch for SetupCardUpdate. #define NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT 0x100000 @@ -737,6 +746,18 @@ Result nsGetApplicationDeliveryInfoHash(const NsApplicationDeliveryInfo *info, s */ Result nsGetApplicationTerminateResult(u64 application_id, Result *res); +/** + * @brief GetApplicationRightsOnClient + * @note Only available on [6.0.0+]. + * @param[out] rights Output array of \ref NsApplicationRightsOnClient. + * @param[in] count Size of the rights array in entries. qlaunch uses value 3 for this. + * @param[in] application_id ApplicationId + * @param[in] uid \ref AccountUid, can optionally be all-zero. + * @param[in] flags Flags. Official sw hard-codes this to value 0x3. + * @param[out] total_out Total output entries. + */ +Result nsGetApplicationRightsOnClient(NsApplicationRightsOnClient *rights, s32 count, u64 application_id, AccountUid uid, u32 flags, s32 *total_out); + /** * @brief RequestNoDownloadRightsErrorResolution * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index 3fa3b530..35ac9c4f 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -940,6 +940,23 @@ Result nsGetApplicationTerminateResult(u64 application_id, Result *res) { return serviceDispatchInOut(&g_nsAppManSrv, 2100, application_id, *res); } +Result nsGetApplicationRightsOnClient(NsApplicationRightsOnClient *rights, s32 count, u64 application_id, AccountUid uid, u32 flags, s32 *total_out) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u32 flags; + u32 pad; + u64 application_id; + AccountUid uid; + } in = { flags, 0, application_id, uid }; + + return serviceDispatchInOut(&g_nsAppManSrv, 2050, in, *total_out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { rights, count*sizeof(NsApplicationRightsOnClient) } }, + ); +} + Result nsRequestNoDownloadRightsErrorResolution(AsyncValue *a, u64 application_id) { if (hosversionBefore(9,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); From 73047b09fddec7d17bf0559422ecd39a2c63a746 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 17 Feb 2020 13:14:18 -0800 Subject: [PATCH 14/17] spl: fix rsa key accessors on >= 5.x --- nx/include/switch/services/spl.h | 4 +- nx/source/services/spl.c | 90 +++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/nx/include/switch/services/spl.h b/nx/include/switch/services/spl.h index 4057d75b..9761ec2b 100644 --- a/nx/include/switch/services/spl.h +++ b/nx/include/switch/services/spl.h @@ -109,13 +109,13 @@ Result splCryptoGetSecurityEngineEvent(Event *out_event); Result splRsaDecryptPrivateKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version, void *dst, size_t dst_size); -Result splSslLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version); +Result splSslLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size); Result splSslSecureExpMod(const void *input, const void *modulus, void *dst); Result splEsLoadRsaOaepKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version); Result splEsUnwrapRsaOaepWrappedTitlekey(const void *rsa_wrapped_titlekey, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_titlekey); Result splEsUnwrapAesWrappedTitlekey(const void *aes_wrapped_titlekey, u32 key_generation, void *out_sealed_titlekey); -Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version); +Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size); Result splEsSecureExpMod(const void *input, const void *modulus, void *dst); Result splEsUnwrapElicenseKey(const void *rsa_wrapped_elicense_key, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_elicense_key); Result splEsLoadElicenseKey(const void *sealed_elicense_key, u32 keyslot); diff --git a/nx/source/services/spl.c b/nx/source/services/spl.c index 239d56b0..bf8bd412 100644 --- a/nx/source/services/spl.c +++ b/nx/source/services/spl.c @@ -294,25 +294,42 @@ Result splCryptoGetSecurityEngineEvent(Event *out_event) { /* SPL IRsaService functionality. NOTE: IRsaService is not a real part of inheritance, unlike ICryptoService/IGeneralService. */ Result splRsaDecryptPrivateKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version, void *dst, size_t dst_size) { - const struct { - SplKey sealed_kek; - SplKey wrapped_key; - u32 version; - } in = { *((const SplKey *)sealed_kek), *((const SplKey *)wrapped_key), version }; - return serviceDispatchIn(_splGetRsaSrv(), 13, in, - .buffer_attrs = { - SfBufferAttr_HipcPointer | SfBufferAttr_Out, - SfBufferAttr_HipcPointer | SfBufferAttr_In, - }, - .buffers = { - { dst, dst_size }, - { wrapped_rsa_key, wrapped_rsa_key_size }, - }, - ); + if (hosversionBefore(5,0,0)) { + const struct { + SplKey sealed_kek; + SplKey wrapped_key; + u32 version; + } in = { *((const SplKey *)sealed_kek), *((const SplKey *)wrapped_key), version }; + return serviceDispatchIn(_splGetRsaSrv(), 13, in, + .buffer_attrs = { + SfBufferAttr_HipcPointer | SfBufferAttr_Out, + SfBufferAttr_HipcPointer | SfBufferAttr_In, + }, + .buffers = { + { dst, dst_size }, + { wrapped_rsa_key, wrapped_rsa_key_size }, + }, + ); + } else { + const struct { + SplKey sealed_kek; + SplKey wrapped_key; + } in = { *((const SplKey *)sealed_kek), *((const SplKey *)wrapped_key) }; + return serviceDispatchIn(_splGetRsaSrv(), 13, in, + .buffer_attrs = { + SfBufferAttr_HipcPointer | SfBufferAttr_Out, + SfBufferAttr_HipcPointer | SfBufferAttr_In, + }, + .buffers = { + { dst, dst_size }, + { wrapped_rsa_key, wrapped_rsa_key_size }, + }, + ); + } } /* Helper function for RSA key importing. */ -NX_INLINE Result _splImportSecureExpModKey(Service* srv, u32 cmd_id, const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { +static Result _splImportSecureExpModKeyDeprecated(Service* srv, u32 cmd_id, const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { const struct { SplKey sealed_kek; SplKey wrapped_key; @@ -328,7 +345,22 @@ NX_INLINE Result _splImportSecureExpModKey(Service* srv, u32 cmd_id, const void ); } -NX_INLINE Result _splSecureExpMod(Service* srv, u32 cmd_id, const void *input, const void *modulus, void *dst) { +static Result _splImportSecureExpModKey(Service* srv, u32 cmd_id, const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size) { + const struct { + SplKey sealed_kek; + SplKey wrapped_key; + } in = { *((const SplKey *)sealed_kek), *((const SplKey *)wrapped_key) }; + return serviceDispatchIn(srv, cmd_id, in, + .buffer_attrs = { + SfBufferAttr_HipcPointer | SfBufferAttr_In, + }, + .buffers = { + { wrapped_rsa_key, wrapped_rsa_key_size }, + }, + ); +} + +static Result _splSecureExpMod(Service* srv, u32 cmd_id, const void *input, const void *modulus, void *dst) { return serviceDispatch(srv, cmd_id, .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out, @@ -344,11 +376,11 @@ NX_INLINE Result _splSecureExpMod(Service* srv, u32 cmd_id, const void *input, c } /* SPL ISslService functionality. */ -Result splSslLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { +Result splSslLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size) { if (hosversionBefore(5,0,0)) { return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); } - return _splImportSecureExpModKey(&g_splSslSrv, 26, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + return _splImportSecureExpModKey(&g_splSslSrv, 26, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size); } Result splSslSecureExpMod(const void *input, const void *modulus, void *dst) { @@ -359,7 +391,7 @@ Result splSslSecureExpMod(const void *input, const void *modulus, void *dst) { } /* SPL IEsService functionality. */ -NX_INLINE Result _splUnwrapRsaOaepWrappedKey(Service *srv, u32 cmd_id, const void *rsa_wrapped_key, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_key) { +static Result _splUnwrapRsaOaepWrappedKey(Service *srv, u32 cmd_id, const void *rsa_wrapped_key, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_key) { return serviceDispatchInOut(srv, cmd_id, key_generation, *((SplKey *)out_sealed_key), .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In, @@ -374,7 +406,7 @@ NX_INLINE Result _splUnwrapRsaOaepWrappedKey(Service *srv, u32 cmd_id, const voi ); } -NX_INLINE Result _splLoadContentKey(Service *srv, u32 cmd_id, const void *sealed_key, u32 keyslot) { +static Result _splLoadContentKey(Service *srv, u32 cmd_id, const void *sealed_key, u32 keyslot) { const struct { SplKey sealed_key; u32 keyslot; @@ -383,7 +415,11 @@ NX_INLINE Result _splLoadContentKey(Service *srv, u32 cmd_id, const void *sealed } Result splEsLoadRsaOaepKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { - return _splImportSecureExpModKey(_splGetEsSrv(), 17, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + if (hosversionBefore(5,0,0)) { + return _splImportSecureExpModKeyDeprecated(_splGetEsSrv(), 17, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + } else { + return _splImportSecureExpModKey(_splGetEsSrv(), 17, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size); + } } Result splEsUnwrapRsaOaepWrappedTitlekey(const void *rsa_wrapped_titlekey, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_titlekey) { @@ -401,11 +437,11 @@ Result splEsUnwrapAesWrappedTitlekey(const void *aes_wrapped_titlekey, u32 key_g return serviceDispatchInOut(_splGetEsSrv(), 20, in, *((SplKey *)out_sealed_titlekey)); } -Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { +Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size) { if (hosversionBefore(5,0,0)) { return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); } - return _splImportSecureExpModKey(&g_splEsSrv, 28, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + return _splImportSecureExpModKey(&g_splEsSrv, 28, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size); } Result splEsSecureExpMod(const void *input, const void *modulus, void *dst) { @@ -431,7 +467,11 @@ Result splEsLoadElicenseKey(const void *sealed_elicense_key, u32 keyslot) { /* SPL IFsService functionality. */ Result splFsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { - return _splImportSecureExpModKey(_splGetFsSrv(), 9, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + if (hosversionBefore(5,0,0)) { + return _splImportSecureExpModKeyDeprecated(_splGetFsSrv(), 9, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); + } else { + return _splImportSecureExpModKey(_splGetFsSrv(), 9, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size); + } } Result splFsSecureExpMod(const void *input, const void *modulus, void *dst) { From 0db4f8a953182d704d3adb7aa091f859326e99a4 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Tue, 18 Feb 2020 10:26:35 -0500 Subject: [PATCH 15/17] ns: Added structs: NsApplicationViewDeprecated, NsApplicationView, NsPromotionInfo, NsApplicationViewWithPromotionInfo. Added cmds: nsGetApplicationViewDeprecated, nsGetApplicationView, nsGetApplicationViewDownloadErrorContext, nsGetApplicationViewWithPromotionInfo, nsGetPromotionInfo. --- nx/include/switch/services/ns.h | 92 +++++++++++++++++++++++++++++++++ nx/source/services/ns.c | 75 +++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index 77c879b8..3268fdcb 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -12,6 +12,7 @@ #include "../services/async.h" #include "../services/acc.h" #include "../services/fs.h" +#include "../applets/error.h" #include "../kernel/event.h" #include "../kernel/tmem.h" @@ -82,6 +83,53 @@ typedef struct { u8 unk_x11[7]; ///< Unknown. } NsApplicationRecord; +/// ApplicationViewDeprecated. The below comments are for the \ref NsApplicationView to NsApplicationViewDeprecated conversion done by \ref nsGetApplicationViewDeprecated on newer system-versions. +typedef struct { + u64 application_id; ///< Same as NsApplicationView::application_id. + u8 unk_x8[0x4]; ///< Same as NsApplicationView::unk_x8. + u32 flags; ///< Same as NsApplicationView::flags. + u8 unk_x10[0x10]; ///< Same as NsApplicationView::unk_x10. + u32 unk_x20; ///< Same as NsApplicationView::unk_x20. + u16 unk_x24; ///< Same as NsApplicationView::unk_x24. + u8 unk_x26[0x2]; ///< Cleared to zero. + u8 unk_x28[0x10]; ///< Same as NsApplicationView::unk_x30. + u32 unk_x38; ///< Same as NsApplicationView::unk_x40. + u8 unk_x3c; ///< Same as NsApplicationView::unk_x44. + u8 unk_x3d[3]; ///< Cleared to zero. +} NsApplicationViewDeprecated; + +/// ApplicationView +typedef struct { + u64 application_id; ///< ApplicationId. + u8 unk_x8[0x4]; ///< Unknown. + u32 flags; ///< Flags. + u8 unk_x10[0x10]; ///< Unknown. + u32 unk_x20; ///< Unknown. + u16 unk_x24; ///< Unknown. + u8 unk_x26[0x2]; ///< Unknown. + u8 unk_x28[0x8]; ///< Unknown. + u8 unk_x30[0x10]; ///< Unknown. + u32 unk_x40; ///< Unknown. + u8 unk_x44; ///< Unknown. + u8 unk_x45[0xb]; ///< Unknown. +} NsApplicationView; + +/// NsPromotionInfo +typedef struct { + u64 start_timestamp; ///< POSIX timestamp for the promotion start. + u64 end_timestamp; ///< POSIX timestamp for the promotion end. + s64 remaining_time; ///< Remaining time until the promotion ends, in nanoseconds ({end_timestamp - current_time} converted to nanoseconds). + u8 unk_x18[0x4]; ///< Not set, left at zero. + u8 flags; ///< Flags. Bit0: whether the PromotionInfo is valid (including bit1). Bit1 clear: remaining_time is set. + u8 pad[3]; ///< Padding. +} NsPromotionInfo; + +/// NsApplicationViewWithPromotionInfo +typedef struct { + NsApplicationView view; ///< \ref NsApplicationView + NsPromotionInfo promotion; ///< \ref NsPromotionInfo +} NsApplicationViewWithPromotionInfo; + /// LaunchProperties typedef struct { u64 program_id; ///< program_id. @@ -186,6 +234,15 @@ Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entr */ Result nsGetApplicationRecordUpdateSystemEvent(Event* out_event); +/** + * @brief GetApplicationViewDeprecated + * @note On [3.0.0+] you should generally use \ref nsGetApplicationView instead. + * @param[out] out Output array of \ref NsApplicationViewDeprecated. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationViewDeprecated(NsApplicationViewDeprecated *views, const u64 *application_ids, s32 count); + /** * @brief DeleteApplicationEntity * @param[in] application_id ApplicationId. @@ -550,6 +607,32 @@ Result nsNeedsSystemUpdateToFormatSdCard(bool *out); */ Result nsGetLastSdCardFormatUnexpectedResult(void); +/** + * @brief GetApplicationView + * @note Only available on [3.0.0+], on prior system-versions use \ref nsGetApplicationViewDeprecated instead. + * @param[out] out Output array of \ref NsApplicationView. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationView(NsApplicationView *views, const u64 *application_ids, s32 count); + +/** + * @brief GetApplicationViewDownloadErrorContext + * @note Only available on [4.0.0+]. + * @param[in] application_id ApplicationId + * @param[out] context \ref ErrorContext + */ +Result nsGetApplicationViewDownloadErrorContext(u64 application_id, ErrorContext *context); + +/** + * @brief GetApplicationViewWithPromotionInfo + * @note Only available on [8.0.0+]. + * @param[out] out Output array of \ref NsApplicationViewWithPromotionInfo. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationViewWithPromotionInfo(NsApplicationViewWithPromotionInfo *out, const u64 *application_ids, s32 count); + /** * @brief RequestDownloadApplicationPrepurchasedRights * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. @@ -776,6 +859,15 @@ Result nsRequestNoDownloadRightsErrorResolution(AsyncValue *a, u64 application_i */ Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id); +/** + * @brief GetPromotionInfo + * @note Only available on [8.0.0+]. + * @param[out] promotion \ref NsPromotionInfo + * @param application_id ApplicationId. + * @param[in] uid \ref AccountUid + */ +Result nsGetPromotionInfo(NsPromotionInfo *promotion, u64 application_id, AccountUid uid); + ///@} ///@name IRequestServerStopper diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index 35ac9c4f..abc2ca6b 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -245,6 +245,19 @@ Result nsGetApplicationRecordUpdateSystemEvent(Event* out_event) { return _nsCmdGetEvent(&g_nsAppManSrv, out_event, true, 2); } +Result nsGetApplicationViewDeprecated(NsApplicationViewDeprecated *views, const u64 *application_ids, s32 count) { + return serviceDispatch(&g_nsAppManSrv, 3, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { views, count*sizeof(NsApplicationViewDeprecated) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + Result nsDeleteApplicationEntity(u64 application_id) { return _nsCmdInU64(&g_nsAppManSrv, application_id, 4); } @@ -652,6 +665,48 @@ Result nsGetLastSdCardFormatUnexpectedResult(void) { return _nsCmdNoIO(&g_nsAppManSrv, 1502); } +Result nsGetApplicationView(NsApplicationView *views, const u64 *application_ids, s32 count) { + if (hosversionBefore(3,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_nsAppManSrv, 1701, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { views, count*sizeof(NsApplicationView) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + +Result nsGetApplicationViewDownloadErrorContext(u64 application_id, ErrorContext *context) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchIn(&g_nsAppManSrv, 1703, application_id, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { context, sizeof(*context) } }, + ); +} + +Result nsGetApplicationViewWithPromotionInfo(NsApplicationViewWithPromotionInfo *out, const u64 *application_ids, s32 count) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_nsAppManSrv, 1704, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { out, count*sizeof(NsApplicationViewWithPromotionInfo) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + Result nsRequestDownloadApplicationPrepurchasedRights(AsyncResult *a, u64 application_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -977,6 +1032,26 @@ Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id) return _nsCmdInU64OutAsyncValue(&g_nsAppManSrv, a, application_id, 2352); } +Result nsGetPromotionInfo(NsPromotionInfo *promotion, u64 application_id, AccountUid uid) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + // These are arrays, but official sw uses hard-coded value 1 for array-count. + + return serviceDispatch(&g_nsAppManSrv, 2400, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { promotion, sizeof(NsPromotionInfo) }, + { &application_id, sizeof(u64) }, + { &uid, sizeof(AccountUid) }, + }, + ); +} + // IRequestServerStopper void nsRequestServerStopperClose(NsRequestServerStopper *r) { From 86a5aa446695573ddea594199357185488a08f19 Mon Sep 17 00:00:00 2001 From: shchmue Date: Tue, 18 Feb 2020 11:56:31 -0700 Subject: [PATCH 16/17] Correct structs and finish adding all set:cal calls (#373) --- nx/include/switch/services/set.h | 289 +++++++++++++++++++++++++++++-- nx/source/services/set.c | 202 +++++++++++++++++++++ 2 files changed, 475 insertions(+), 16 deletions(-) diff --git a/nx/include/switch/services/set.h b/nx/include/switch/services/set.h index fda2445b..e60a6911 100644 --- a/nx/include/switch/services/set.h +++ b/nx/include/switch/services/set.h @@ -271,27 +271,35 @@ typedef struct { } SetCalAccelerometerScale; typedef struct { + u32 size; u8 cert[0x70]; } SetCalAmiiboEcdsaCertificate; typedef struct { + u32 size; u8 cert[0x20]; } SetCalAmiiboEcqvBlsCertificate; typedef struct { - u8 key[0x44]; + u32 size; + u8 key[0x40]; + u32 generation; } SetCalAmiiboEcqvBlsKey; typedef struct { + u32 size; u8 cert[0x90]; } SetCalAmiiboEcqvBlsRootCertificate; typedef struct { + u32 size; u8 cert[0x14]; } SetCalAmiiboEcqvCertificate; typedef struct { - u8 key[0x54]; + u32 size; + u8 key[0x50]; + u32 generation; } SetCalAmiiboKey; typedef struct { @@ -319,16 +327,17 @@ typedef struct { } SetCalConsoleSixAxisSensorHorizontalOffset; typedef struct { - u32 code[0x4]; ///< Country code. + char code[0x3]; ///< Country code. } SetCalCountryCode; typedef struct { - u32 offset; ///< Relative to current position. - u8 cert[0x17C]; + u8 cert[0x180]; } SetCalEccB233DeviceCertificate; typedef struct { - u8 key[0x58]; + u32 size; + u8 key[0x50]; + u32 generation; } SetCalEccB233DeviceKey; typedef struct { @@ -338,6 +347,7 @@ typedef struct { typedef struct { u32 size; ///< Size of the entire key. u8 key[0x130]; + u32 generation; } SetCalGameCardKey; typedef struct { @@ -353,17 +363,17 @@ typedef struct { } SetCalMacAddress; typedef struct { - u32 offset; ///< Relative to current position. - u8 cert[0x23C]; + u8 cert[0x240]; } SetCalRsa2048DeviceCertificate; typedef struct { u32 size; ///< Size of the entire key. u8 key[0x240]; + u32 generation; } SetCalRsa2048DeviceKey; typedef struct { - u8 number[0x18]; + char number[0x18]; } SetCalSerialNumber; typedef struct { @@ -378,6 +388,7 @@ typedef struct { typedef struct { u32 size; ///< Size of the entire key. u8 key[0x130]; + u32 generation; } SetCalSslKey; typedef struct { @@ -1017,23 +1028,269 @@ void setcalExit(void); /// Gets the Service object for the actual setcal service session. Service* setcalGetServiceSession(void); -/// Gets the \ref SetCalEccB233DeviceCertificate. +/** + * @brief Gets the \ref SetCalBdAddress. + * @param[out] out \ref SetCalBdAddress + */ +Result setcalGetBdAddress(SetCalBdAddress *out); + +/** + * @brief Gets the \ref SetCalConfigurationId1. + * @param[out] out \ref SetCalConfigurationId1 + */ +Result setcalGetConfigurationId1(SetCalConfigurationId1 *out); + +/** + * @brief Gets the \ref SetCalAccelerometerOffset. + * @param[out] out \ref SetCalAccelerometerOffset + */ +Result setcalGetAccelerometerOffset(SetCalAccelerometerOffset *out); + +/** + * @brief Gets the \ref SetCalAccelerometerScale. + * @param[out] out \ref SetCalAccelerometerScale + */ +Result setcalGetAccelerometerScale(SetCalAccelerometerScale *out); + +/** + * @brief Gets the \ref SetCalAccelerometerOffset. + * @param[out] out \ref SetCalAccelerometerOffset + */ +Result setcalGetGyroscopeOffset(SetCalAccelerometerOffset *out); + +/** + * @brief Gets the \ref SetCalGyroscopeScale. + * @param[out] out \ref SetCalGyroscopeScale + */ +Result setcalGetGyroscopeScale(SetCalGyroscopeScale *out); + +/** + * @brief Gets the \ref SetCalMacAddress. + * @param[out] out \ref SetCalMacAddress + */ +Result setcalGetWirelessLanMacAddress(SetCalMacAddress *out); + +/** + * @brief GetWirelessLanCountryCodeCount + * @param[out] out_count Output count + */ +Result setcalGetWirelessLanCountryCodeCount(s32 *out_count); + +/** + * @brief GetWirelessLanCountryCodes + * @param[out] total_out Total output entries. + * @param[out] codes Output array of \ref SetCalCountryCode. + * @param[in] count Size of the versions array in entries. + */ +Result setcalGetWirelessLanCountryCodes(s32 *total_out, SetCalCountryCode *codes, s32 count); + +/** + * @brief Gets the \ref SetCalSerialNumber. + * @param[out] out \ref SetCalSerialNumber + */ +Result setcalGetSerialNumber(SetCalSerialNumber *out); + +/** + * @brief SetInitialSystemAppletProgramId + * @param[in] program_id input ProgramId. + */ +Result setcalSetInitialSystemAppletProgramId(u64 program_id); + +/** + * @brief SetOverlayDispProgramId + * @param[in] program_id input ProgramId. + */ +Result setcalSetOverlayDispProgramId(u64 program_id); + +/** + * @brief Gets the \ref SetBatteryLot. + * @param[out] out \ref SetBatteryLot + */ +Result setcalGetBatteryLot(SetBatteryLot *out); + +/** + * @brief Gets the \ref SetCalEccB233DeviceCertificate. + * @param[out] out \ref SetCalEccB233DeviceCertificate + */ Result setcalGetEciDeviceCertificate(SetCalEccB233DeviceCertificate *out); -/// Gets the \ref SetCalRsa2048DeviceCertificate. +/** + * @brief Gets the \ref SetCalRsa2048DeviceCertificate. + * @param[out] out \ref SetCalRsa2048DeviceCertificate + */ Result setcalGetEticketDeviceCertificate(SetCalRsa2048DeviceCertificate *out); -/// Gets the \ref SetCalSslKey. +/** + * @brief Gets the \ref SetCalSslKey. + * @param[out] out \ref SetCalSslKey + */ Result setcalGetSslKey(SetCalSslKey *out); -/// Gets the \ref SetCalSslCertificate. +/** + * @brief Gets the \ref SetCalSslCertificate. + * @param[out] out \ref SetCalSslCertificate + */ Result setcalGetSslCertificate(SetCalSslCertificate *out); -/// Gets the \ref SetCalGameCardKey. +/** + * @brief Gets the \ref SetCalGameCardKey. + * @param[out] out \ref SetCalGameCardKey + */ Result setcalGetGameCardKey(SetCalGameCardKey *out); -/// Gets the \ref SetCalGameCardCertificate. +/** + * @brief Gets the \ref SetCalGameCardCertificate. + * @param[out] out \ref SetCalGameCardCertificate + */ Result setcalGetGameCardCertificate(SetCalGameCardCertificate *out); -/// Gets the \ref SetCalRsa2048DeviceKey. +/** + * @brief Gets the \ref SetCalEccB233DeviceKey. + * @param[out] out \ref SetCalEccB233DeviceKey + */ +Result setcalGetEciDeviceKey(SetCalEccB233DeviceKey *out); + +/** + * @brief Gets the \ref SetCalRsa2048DeviceKey. + * @param[out] out \ref SetCalRsa2048DeviceKey + */ Result setcalGetEticketDeviceKey(SetCalRsa2048DeviceKey *out); + +/** + * @brief Gets the \ref SetCalSpeakerParameter. + * @param[out] out \ref SetCalSpeakerParameter + */ +Result setcalGetSpeakerParameter(SetCalSpeakerParameter *out); + +/** + * @brief GetLcdVendorId + * @note Only available on [4.0.0+]. + * @param[out] out_vendor_id Output LcdVendorId. + */ +Result setcalGetLcdVendorId(u32 *out_vendor_id); + +/** + * @brief Gets the \ref SetCalRsa2048DeviceCertificate. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalRsa2048DeviceCertificate + */ +Result setcalGetEciDeviceCertificate2(SetCalRsa2048DeviceCertificate *out); + +/** + * @brief Gets the \ref SetCalRsa2048DeviceKey. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalRsa2048DeviceKey + */ +Result setcalGetEciDeviceKey2(SetCalRsa2048DeviceKey *out); + +/** + * @brief Gets the \ref SetCalAmiiboKey. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboKey + */ +Result setcalGetAmiiboKey(SetCalAmiiboKey *out); + +/** + * @brief Gets the \ref SetCalAmiiboEcqvCertificate. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboEcqvCertificate + */ +Result setcalGetAmiiboEcqvCertificate(SetCalAmiiboEcqvCertificate *out); + +/** + * @brief Gets the \ref SetCalAmiiboEcdsaCertificate. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboEcdsaCertificate + */ +Result setcalGetAmiiboEcdsaCertificate(SetCalAmiiboEcdsaCertificate *out); + +/** + * @brief Gets the \ref SetCalAmiiboEcqvBlsKey. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboEcqvBlsKey + */ +Result setcalGetAmiiboEcqvBlsKey(SetCalAmiiboEcqvBlsKey *out); + +/** + * @brief Gets the \ref SetCalAmiiboEcqvBlsCertificate. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboEcqvBlsCertificate + */ +Result setcalGetAmiiboEcqvBlsCertificate(SetCalAmiiboEcqvBlsCertificate *out); + +/** + * @brief Gets the \ref SetCalAmiiboEcqvBlsRootCertificate. + * @note Only available on [5.0.0+]. + * @param[out] out \ref SetCalAmiiboEcqvBlsRootCertificate + */ +Result setcalGetAmiiboEcqvBlsRootCertificate(SetCalAmiiboEcqvBlsRootCertificate *out); + +/** + * @brief GetUsbTypeCPowerSourceCircuitVersion + * @note Only available on [5.0.0+]. + * @param[out] out_version Output UsbTypeCPowerSourceCircuitVersion. + */ +Result setcalGetUsbTypeCPowerSourceCircuitVersion(u8 *out_version); + +/** + * @brief GetAnalogStickModuleTypeL + * @note Only available on [8.1.1+]. + * @param[out] out_version Output AnalogStickModuleType. + */ +Result setcalGetAnalogStickModuleTypeL(u8 *out_type); + +/** + * @brief Gets the \ref SetCalAnalogStickModelParameter. + * @note Only available on [8.1.1+]. + * @param[out] out \ref SetCalAnalogStickModelParameter + */ +Result setcalGetAnalogStickModelParameterL(SetCalAnalogStickModelParameter *out); + +/** + * @brief Gets the \ref SetCalAnalogStickFactoryCalibration. + * @note Only available on [8.1.1+]. + * @param[out] out \ref SetCalAnalogStickFactoryCalibration + */ +Result setcalGetAnalogStickFactoryCalibrationL(SetCalAnalogStickFactoryCalibration *out); + +/** + * @brief GetAnalogStickModuleTypeR + * @note Only available on [8.1.1+]. + * @param[out] out_version Output AnalogStickModuleType. + */ +Result setcalGetAnalogStickModuleTypeR(u8 *out_type); + +/** + * @brief Gets the \ref SetCalAnalogStickModelParameter. + * @note Only available on [8.1.1+]. + * @param[out] out \ref SetCalAnalogStickModelParameter + */ +Result setcalGetAnalogStickModelParameterR(SetCalAnalogStickModelParameter *out); + +/** + * @brief Gets the \ref SetCalAnalogStickFactoryCalibration. + * @note Only available on [8.1.1+]. + * @param[out] out \ref SetCalAnalogStickFactoryCalibration + */ +Result setcalGetAnalogStickFactoryCalibrationR(SetCalAnalogStickFactoryCalibration *out); + +/** + * @brief GetConsoleSixAxisSensorModuleType + * @note Only available on [8.1.1+]. + * @param[out] out_version Output ConsoleSixAxisSensorModuleType. + */ +Result setcalGetConsoleSixAxisSensorModuleType(u8 *out_type); + +/** + * @brief Gets the \ref SetCalConsoleSixAxisSensorHorizontalOffset. + * @note Only available on [8.1.1+]. + * @param[out] out \ref SetCalConsoleSixAxisSensorHorizontalOffset + */ +Result setcalGetConsoleSixAxisSensorHorizontalOffset(SetCalConsoleSixAxisSensorHorizontalOffset *out); + +/** + * @brief GetBatteryVersion + * @note Only available on [6.0.0+]. + * @param[out] out_version Output BatteryVersion. + */ +Result setcalGetBatteryVersion(u8 *out_version); diff --git a/nx/source/services/set.c b/nx/source/services/set.c index 131a5e07..67d9dd92 100644 --- a/nx/source/services/set.c +++ b/nx/source/services/set.c @@ -781,6 +781,61 @@ Result setsysSetTouchScreenMode(SetSysTouchScreenMode mode) { return _setCmdInU32NoOut(&g_setsysSrv, mode, 188); } +Result setcalGetBdAddress(SetCalBdAddress *out) { + return serviceDispatchOut(&g_setsysSrv, 0, *out); +} + +Result setcalGetConfigurationId1(SetCalConfigurationId1 *out) { + return serviceDispatchOut(&g_setsysSrv, 1, *out); +} + +Result setcalGetAccelerometerOffset(SetCalAccelerometerOffset *out) { + return serviceDispatchOut(&g_setsysSrv, 2, *out); +} + +Result setcalGetAccelerometerScale(SetCalAccelerometerScale *out) { + return serviceDispatchOut(&g_setsysSrv, 3, *out); +} + +Result setcalGetGyroscopeOffset(SetCalAccelerometerOffset *out) { + return serviceDispatchOut(&g_setsysSrv, 4, *out); +} + +Result setcalGetGyroscopeScale(SetCalGyroscopeScale *out) { + return serviceDispatchOut(&g_setsysSrv, 5, *out); +} + +Result setcalGetWirelessLanMacAddress(SetCalMacAddress *out) { + return serviceDispatchOut(&g_setsysSrv, 6, *out); +} + +Result setcalGetWirelessLanCountryCodeCount(s32 *out_count) { + return _setCmdNoInOutU32(&g_setsysSrv, (u32*)out_count, 7); +} + +Result setcalGetWirelessLanCountryCodes(s32 *total_out, SetCalCountryCode *codes, s32 count) { + return serviceDispatchOut(&g_setsysSrv, 8, *total_out, + .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out }, + .buffers = { { codes, count*sizeof(SetCalCountryCode) } }, + ); +} + +Result setcalGetSerialNumber(SetCalSerialNumber *out) { + return serviceDispatchOut(&g_setsysSrv, 9, *out); +} + +Result setcalSetInitialSystemAppletProgramId(u64 program_id) { + return _setCmdInU64NoOut(&g_setsysSrv, program_id, 10); +} + +Result setcalSetOverlayDispProgramId(u64 program_id) { + return _setCmdInU64NoOut(&g_setsysSrv, program_id, 11); +} + +Result setcalGetBatteryLot(SetBatteryLot *out) { + return serviceDispatchOut(&g_setsysSrv, 12, *out); +} + Result setcalGetEciDeviceCertificate(SetCalEccB233DeviceCertificate *out) { return serviceDispatch(&g_setcalSrv, 14, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, @@ -823,9 +878,156 @@ Result setcalGetGameCardCertificate(SetCalGameCardCertificate *out) { ); } +Result setcalGetEciDeviceKey(SetCalEccB233DeviceKey *out) { + return serviceDispatchOut(&g_setcalSrv, 20, *out); +} + Result setcalGetEticketDeviceKey(SetCalRsa2048DeviceKey *out) { return serviceDispatch(&g_setcalSrv, 21, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out, sizeof(SetCalRsa2048DeviceKey) } }, ); } + +Result setcalGetSpeakerParameter(SetCalSpeakerParameter *out) { + return serviceDispatchOut(&g_setcalSrv, 22, *out); +} + +Result setcalGetLcdVendorId(u32 *out_vendor_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU32(&g_setcalSrv, out_vendor_id, 23); +} + +Result setcalGetEciDeviceCertificate2(SetCalRsa2048DeviceCertificate *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_setcalSrv, 24, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out, sizeof(SetCalRsa2048DeviceCertificate) } }, + ); +} + +Result setcalGetEciDeviceKey2(SetCalRsa2048DeviceKey *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_setcalSrv, 25, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out, sizeof(SetCalRsa2048DeviceKey) } }, + ); +} + +Result setcalGetAmiiboKey(SetCalAmiiboKey *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 26, *out); +} + +Result setcalGetAmiiboEcqvCertificate(SetCalAmiiboEcqvCertificate *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 27, *out); +} + +Result setcalGetAmiiboEcdsaCertificate(SetCalAmiiboEcdsaCertificate *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 28, *out); +} + +Result setcalGetAmiiboEcqvBlsKey(SetCalAmiiboEcqvBlsKey *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 29, *out); +} + +Result setcalGetAmiiboEcqvBlsCertificate(SetCalAmiiboEcqvBlsCertificate *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 30, *out); +} + +Result setcalGetAmiiboEcqvBlsRootCertificate(SetCalAmiiboEcqvBlsRootCertificate *out) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 31, *out); +} + +Result setcalGetUsbTypeCPowerSourceCircuitVersion(u8 *out_version) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU8(&g_setcalSrv, out_version, 32); +} + +Result setcalGetAnalogStickModuleTypeL(u8 *out_type) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU8(&g_setcalSrv, out_type, 33); +} + +Result setcalGetAnalogStickModelParameterL(SetCalAnalogStickModelParameter *out) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 34, *out); +} + +Result setcalGetAnalogStickFactoryCalibrationL(SetCalAnalogStickFactoryCalibration *out) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 35, *out); +} + +Result setcalGetAnalogStickModuleTypeR(u8 *out_type) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU8(&g_setcalSrv, out_type, 36); +} + +Result setcalGetAnalogStickModelParameterR(SetCalAnalogStickModelParameter *out) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 37, *out); +} + +Result setcalGetAnalogStickFactoryCalibrationR(SetCalAnalogStickFactoryCalibration *out) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 38, *out); +} + +Result setcalGetConsoleSixAxisSensorModuleType(u8 *out_type) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU8(&g_setcalSrv, out_type, 39); +} + +Result setcalGetConsoleSixAxisSensorHorizontalOffset(SetCalConsoleSixAxisSensorHorizontalOffset *out) { + if (hosversionBefore(8,1,1)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchOut(&g_setcalSrv, 40, *out); +} + +Result setcalGetBatteryVersion(u8 *out_version) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _setCmdNoInOutU8(&g_setcalSrv, out_version, 41); +} From 72be2f3bec4899055acf9ddf9bcc6dd7be9807b4 Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Wed, 19 Feb 2020 02:00:24 +0100 Subject: [PATCH 17/17] fix movie write and add comments --- nx/include/switch/services/caps.h | 5 -- nx/include/switch/services/capsc.h | 113 ++++++++++++++++++++++++++++- nx/source/services/capsc.c | 30 ++++---- 3 files changed, 124 insertions(+), 24 deletions(-) diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index da2ad48a..79047cb0 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -200,11 +200,6 @@ typedef struct { u64 unk_x8; ///< Unknown } CapsAlbumCache; -/// AlbumCommitOutput -typedef struct { - u64 unk[4]; ///< Unknown. Official sw sets this to 0. -} CapsAlbumCommitOutput; - /// Gets the ShimLibraryVersion. u64 capsGetShimLibraryVersion(void); diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h index 2f2032ff..a5d81901 100644 --- a/nx/include/switch/services/capsc.h +++ b/nx/include/switch/services/capsc.h @@ -149,7 +149,7 @@ Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size); /** * @brief Reads data from an AlbumMovieReadStream. * @note offset(+size) must not be negative. offset and size must be aligned to 0x40000-bytes. - * @note When offset(+size) goes beyond the size from \ref capsaGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size. + * @note When offset(+size) goes beyond the size from \ref capscGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size. * @note Only available on [4.0.0+]. * @param[in] stream Stream handle. * @param[in] offset Offset. @@ -180,7 +180,7 @@ Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size); * @note Only available on [4.0.0+]. * @param[in] stream Stream handle. * @param[in] offset Offset. - * @param[out] Output data buffer. + * @param[out] buffer Output data buffer. * @param[in] size Data buffer size. * @param[out] actual_size Actual read size. */ @@ -203,18 +203,125 @@ Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShot * @param[in] entry \ref CapsAlbumFileId */ Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id); + +/** + * @brief Finish write to AlbumMovieWriteStream. + * @note Writes copies file from save to destination storage and deletes the temporary file. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscFinishAlbumMovieWriteStream(u64 stream); + +/** + * @brief Closes a finished AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscCommitAlbumMovieWriteStream(u64 stream); + +/** + * @brief Closes an AlbumMovieWriteStream in any state. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscDiscardAlbumMovieWriteStream(u64 stream); + +/** + * @brief Closes an AlbumMovieWriteStream in any state without deleting the temporary file. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream); -Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out); + +/** + * @brief Closes a finished AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] entry \ref CapsAlbumEntry + */ +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumEntry *entry); + +/** + * @brief Start AlbumMovieWriteStream data section. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscStartAlbumMovieWriteStreamDataSection(u64 stream); + +/** + * @brief End AlbumMovieWriteStream data section. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscEndAlbumMovieWriteStreamDataSection(u64 stream); + +/** + * @brief Start AlbumMovieWriteStream meta section. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream); + +/** + * @brief End AlbumMovieWriteStream meta section. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream); + +/** + * @brief Reads data from an AlbumMovieWriteStream. + * @note offset(+size) must not be negative. offset and size must be aligned to 0x40000-bytes. + * @note When offset(+size) goes beyond the size from \ref capscGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[in] offset Offset. + * @param[out] buffer Output data buffer. + * @param[in] size Data buffer size. + * @param[out] actual_size Actual read size. + */ Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size); + +/** + * @brief Write data to an AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[in] offset Offset. + * @param[out] buffer Input data buffer. + * @param[in] size Data buffer size. + */ Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); + +/** + * @brief Write meta data to an AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[in] offset Offset. + * @param[out] buffer Input data buffer. + * @param[in] size Data buffer size. + */ Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); + +/** + * @brief Gets the BrokenReason for an AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + */ Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream); + +/** + * @brief Gets the data size of an AlbumMovieWriteStream. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] size Size of the data section. + */ Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size); + +/** + * @brief Sets the data size of an AlbumMovieWriteStream. + * @note Must not be bigger than 2GiB. + * @note Only available on [4.0.0+]. + * @param[in] stream Stream handle. + * @param[out] size Size of the data section. + */ Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c index ce64e927..c1b2bdfd 100644 --- a/nx/source/services/capsc.c +++ b/nx/source/services/capsc.c @@ -179,7 +179,7 @@ static Result _capscControlReadDataFromAlbumMovieStream(u32 cmd_id, u64 stream, ); } -static Result _capscControlCmdInU8NoOut(u32 cmd_id, u8 inval) { +static Result _capscControlCmdInU64NoOut(u32 cmd_id, u64 inval) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capscControl)) @@ -197,7 +197,7 @@ Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id } Result capscCloseAlbumMovieStream(u64 stream) { - return _capscControlCmdInU8NoOut(2002, stream); + return _capscControlCmdInU64NoOut(2002, stream); } Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size) { @@ -213,7 +213,7 @@ Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* } Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream) { - return _capscControlCmdInU8NoOut(2005, stream); + return _capscControlCmdInU64NoOut(2005, stream); } Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size) { @@ -252,45 +252,43 @@ Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_i } Result capscFinishAlbumMovieWriteStream(u64 stream) { - return _capscControlCmdInU8NoOut(2402, stream); + return _capscControlCmdInU64NoOut(2402, stream); } Result capscCommitAlbumMovieWriteStream(u64 stream) { - return _capscControlCmdInU8NoOut(2403, stream); + return _capscControlCmdInU64NoOut(2403, stream); } Result capscDiscardAlbumMovieWriteStream(u64 stream) { - return _capscControlCmdInU8NoOut(2404, stream); + return _capscControlCmdInU64NoOut(2404, stream); } Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream) { - return _capscControlCmdInU8NoOut(2405, stream); + return _capscControlCmdInU64NoOut(2405, stream); } -Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out) { +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumEntry *entry) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!serviceIsActive(&g_capscControl)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - - return serviceDispatchInOut(&g_capscControl, 2406, stream, *out); + return serviceDispatchInOut(&g_capscControl, 2406, stream, *entry); } Result capscStartAlbumMovieWriteStreamDataSection(u64 stream) { - return _capscControlCmdInU8NoOut(2411, stream); + return _capscControlCmdInU64NoOut(2411, stream); } Result capscEndAlbumMovieWriteStreamDataSection(u64 stream) { - return _capscControlCmdInU8NoOut(2412, stream); + return _capscControlCmdInU64NoOut(2412, stream); } Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream) { - return _capscControlCmdInU8NoOut(2413, stream); + return _capscControlCmdInU64NoOut(2413, stream); } Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream) { - return _capscControlCmdInU8NoOut(2414, stream); + return _capscControlCmdInU64NoOut(2414, stream); } Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size) { @@ -321,7 +319,7 @@ Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffe } Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream) { - return _capscControlCmdInU8NoOut(2431, stream); + return _capscControlCmdInU64NoOut(2431, stream); } Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size) {