mirror of
https://github.com/switchbrew/libnx.git
synced 2025-12-31 06:58:40 +01:00
Merge remote-tracking branch 'upstream/master' into psel-libapplet
This commit is contained in:
commit
304cbe735d
95
Changelog.md
95
Changelog.md
@ -1,5 +1,100 @@
|
||||
# Changelog
|
||||
|
||||
## Version 2.5.0
|
||||
|
||||
#### system
|
||||
* Corrected type of id0 in svcGetInfo.
|
||||
|
||||
#### filesystem
|
||||
* Added fsExtendSaveDataFileSystem, fsOpenCustomStorageFileSystem, fsSetGlobalAccessLogMode, fsGetGlobalAccessLogMode.
|
||||
* Added FsCustomStorageId enum.
|
||||
* Fixed by-name RomFS mount lookups to actually compare the entire name.
|
||||
|
||||
#### graphics
|
||||
* Added binder session argument to nwindowCreate (nwindowCreateFromLayer not affected).
|
||||
* Binder code now supports domain objects.
|
||||
* Fixed bug in nvAddressSpaceCreate.
|
||||
|
||||
#### input
|
||||
* **Explicitly announce support for System/SystemExt layouts, which in turn fixes input on 9.0.0+. It is of utmost importance that all homebrew be recompiled as soon as possible in order to work properly on 9.0.0+.**
|
||||
* **Fixed Hdls to work on 9.0.0+.**
|
||||
* Several Hdls structs were redefined in 9.0.0+ and libnx was updated to reflect the new struct definitions (this is a breaking change). The old structs are still available but they now have a `V7` suffix, and libnx transparently handles conversion to/from the new 9.x structs at runtime on older system versions; so the new structs are *always* used regardless of system version. List of structs affected:
|
||||
* HiddbgHdlsDeviceInfo(V7)
|
||||
* HiddbgHdlsState(V7)
|
||||
* HiddbgHdlsStateListEntry(V7)
|
||||
* HiddbgHdlsStateList(V7)
|
||||
* Added hiddbgGetUniquePadDeviceTypeSetInternal.
|
||||
* Added hidGetNpadInterfaceType.
|
||||
* Added HidNpadInterfaceType, HidDeviceTypeBits, HidDeviceType enums.
|
||||
* Prevent AbstractedPad/VirtualPad commands from being used on 9.0.0+ since they were removed.
|
||||
* Corrected several commands by internally calling hidControllerIDToOfficial.
|
||||
|
||||
#### applet
|
||||
* Added AppletAttribute, AppletProcessLaunchReason, AppletInfo, AppletApplicationLaunchProperty, AppletApplicationLaunchRequestInfo, AppletResourceUsageInfo structs.
|
||||
* Added AppletApplicationExitReason, AppletSystemButtonType, AppletProgramSpecifyKind enums.
|
||||
* Renamed AppletNotificationMessage to AppletMessage.
|
||||
* Renamed AppletLaunchParameterKind_Application to AppletLaunchParameterKind_UserChannel.
|
||||
* Added appletGetServiceSession_* funcs.
|
||||
* Added appletGetAppletInfo.
|
||||
* Changed appletRequestToShutdown/appletRequestToReboot and appletStartShutdownSequenceForOverlay/appletStartRebootSequenceForOverlay on success to enter an infinite sleep loop.
|
||||
* This is also used with `_appletExitProcess` when the exit commands were successful, which is used during `__nx_applet_exit_mode` handling.
|
||||
* Use OpenLibraryAppletProxy command on 3.0.0+ when running appletInitialize for AppletType_LibraryApplet.
|
||||
* Added libappletArgsPop and libappletSetJumpFlag.
|
||||
|
||||
* **ILibraryAppletSelfAccessor**:
|
||||
* Added appletPopInData, appletPushOutData, appletPopInteractiveInData, appletPushInteractiveOutData, appletGetPopInDataEvent, appletGetPopInteractiveInDataEvent.
|
||||
* Added appletCanUseApplicationCore, appletGetMainAppletApplicationControlProperty, appletGetMainAppletStorageId, appletGetDesirableKeyboardLayout.
|
||||
* Added appletPopExtraStorage, appletGetPopExtraStorageEvent, appletUnpopInData, appletUnpopExtraStorage.
|
||||
* Added appletGetIndirectLayerProducerHandle, appletGetMainAppletApplicationDesiredLanguage, appletGetCurrentApplicationId.
|
||||
* Added appletCreateGameMovieTrimmer, appletReserveResourceForMovieOperation, appletUnreserveResourceForMovieOperation.
|
||||
* Added appletGetMainAppletAvailableUsers.
|
||||
* **IProcessWindingController**:
|
||||
* Added appletPushContext, appletPopContext.
|
||||
* **IDebugFunctions**:
|
||||
* Added appletOpenMainApplication, appletPerformSystemButtonPressing, appletInvalidateTransitionLayer, appletRequestLaunchApplicationWithUserAndArgumentForDebug, appletGetAppletResourceUsageInfo.
|
||||
* **ILibraryAppletAccessor**:
|
||||
* Added appletHolderTerminate, appletHolderRequestExitOrTerminate.
|
||||
* **IProcessWindingController**:
|
||||
* Added appletHolderJump.
|
||||
* **IOverlayFunctions**:
|
||||
* Added appletBeginToObserveHidInputForDevelop.
|
||||
* **IHomeMenuFunctions**:
|
||||
* Added appletPopRequestLaunchApplicationForDebug, appletLaunchDevMenu.
|
||||
* **IApplicationCreator**:
|
||||
* Added support for AppletApplication.
|
||||
* Added appletCreateApplication, appletPopLaunchRequestedApplication, appletCreateSystemApplication, appletPopFloatingApplicationForDevelopment.
|
||||
* **ILibraryAppletCreator**:
|
||||
* Added appletTerminateAllLibraryApplets, appletAreAnyLibraryAppletsLeft.
|
||||
* **IApplicationFunctions**:
|
||||
* Added appletGetLaunchStorageInfoForDebug, appletRequestFlushGamePlayingMovieForDebug, appletExitAndRequestToShowThanksMessage.
|
||||
* Added appletExecuteProgram, appletJumpToSubApplicationProgramForDevelopment, appletRestartProgram, and appletGetPreviousProgramIndex.
|
||||
* Added appletCreateMovieMaker and appletPrepareForJit.
|
||||
|
||||
#### libapplets
|
||||
* Added support for launching the Album applet via albumLa.
|
||||
|
||||
#### other services
|
||||
* **Added GRC service support** (video recording, streaming and trimming).
|
||||
* Changes to caps (capture service) wrappers:
|
||||
* Added support for the caps:u service.
|
||||
* Added CapsAlbumFileDateTime, CapsAlbumEntryId, CapsApplicationData, CapsUserIdList, CapsScreenShotAttributeForApplication, CapsScreenShotDecodeOption, CapsApplicationAlbumFileEntry, CapsLoadAlbumScreenShotImageOutputForApplication structs.
|
||||
* Added AlbumReportOption, CapsContentType enums.
|
||||
* Added capsGetShimLibraryVersion (not an actual IPC wrapper).
|
||||
* Added capsGetDefaultStartDateTime, capsGetDefaultEndDateTime, capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry, capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry helper functions.
|
||||
* Added capssuSaveScreenShotWithUserData, capssuSaveScreenShotWithUserIds, capssuSaveScreenShotEx1, capssuSaveScreenShotEx2.
|
||||
* Improved definition of capssuSaveScreenShot and capssuSaveScreenShotEx0.
|
||||
* Improved definition of CapsScreenShotAttribute, CapsApplicationAlbumEntry structs.
|
||||
* Changed caps:su wrapper to call SetShimLibraryVersion on 7.0.0+.
|
||||
* Renamed capsscCaptureScreenshot with capsscCaptureRawImageWithTimeout.
|
||||
* Fixed lr RedirectApplication commands on 9.0.0+.
|
||||
* Renamed lrLrResolveLegalInformationPath to lrLrResolveApplicationLegalInformationPath.
|
||||
* Renamed lrLrRedirectLegalInformationPath to lrLrRedirectApplicationLegalInformationPath.
|
||||
* Added missing fields to NacpStruct and other miscellaneous corrections.
|
||||
* Fixed definition of setsysGetServiceSession.
|
||||
|
||||
#### miscellaneous
|
||||
* Further improvements to overall system stability and other minor adjustments have been made to enhance the user experience.
|
||||
|
||||
## Version 2.4.0
|
||||
|
||||
#### system
|
||||
|
||||
@ -9,7 +9,7 @@ endif
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
export LIBNX_MAJOR := 2
|
||||
export LIBNX_MINOR := 4
|
||||
export LIBNX_MINOR := 5
|
||||
export LIBNX_PATCH := 0
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ CFLAGS := -g -Wall -Werror \
|
||||
$(ARCH) \
|
||||
$(BUILD_CFLAGS)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DSWITCH
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DLIBNX_NO_DEPRECATION
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
|
||||
@ -36,9 +36,13 @@ extern "C" {
|
||||
#include "switch/kernel/detect.h"
|
||||
#include "switch/kernel/random.h"
|
||||
#include "switch/kernel/jit.h"
|
||||
#include "switch/kernel/ipc.h"
|
||||
#include "switch/kernel/ipc.h" // Deprecated
|
||||
#include "switch/kernel/barrier.h"
|
||||
|
||||
#include "switch/sf/hipc.h"
|
||||
#include "switch/sf/cmif.h"
|
||||
#include "switch/sf/service.h"
|
||||
|
||||
#include "switch/services/sm.h"
|
||||
#include "switch/services/smm.h"
|
||||
#include "switch/services/fs.h"
|
||||
@ -47,6 +51,7 @@ extern "C" {
|
||||
#include "switch/services/acc.h"
|
||||
#include "switch/services/apm.h"
|
||||
#include "switch/services/applet.h"
|
||||
#include "switch/services/async.h"
|
||||
#include "switch/services/audin.h"
|
||||
#include "switch/services/audout.h"
|
||||
#include "switch/services/audren.h"
|
||||
@ -78,6 +83,7 @@ extern "C" {
|
||||
#include "switch/services/ns.h"
|
||||
#include "switch/services/ldr.h"
|
||||
#include "switch/services/ro.h"
|
||||
#include "switch/services/ts.h"
|
||||
#include "switch/services/pm.h"
|
||||
#include "switch/services/set.h"
|
||||
#include "switch/services/lr.h"
|
||||
@ -85,6 +91,7 @@ extern "C" {
|
||||
#include "switch/services/ncm.h"
|
||||
#include "switch/services/psc.h"
|
||||
#include "switch/services/caps.h"
|
||||
#include "switch/services/capsu.h"
|
||||
#include "switch/services/capssc.h"
|
||||
#include "switch/services/capssu.h"
|
||||
#include "switch/services/nfc.h"
|
||||
@ -92,6 +99,7 @@ extern "C" {
|
||||
#include "switch/services/pctl.h"
|
||||
#include "switch/services/pdm.h"
|
||||
#include "switch/services/grc.h"
|
||||
#include "switch/services/friends.h"
|
||||
|
||||
#include "switch/display/binder.h"
|
||||
#include "switch/display/parcel.h"
|
||||
@ -111,6 +119,8 @@ extern "C" {
|
||||
#include "switch/audio/driver.h"
|
||||
|
||||
#include "switch/applets/libapplet.h"
|
||||
#include "switch/applets/album_la.h"
|
||||
#include "switch/applets/friends_la.h"
|
||||
#include "switch/applets/pctlauth.h"
|
||||
#include "switch/applets/psel.h"
|
||||
#include "switch/applets/error.h"
|
||||
|
||||
31
nx/include/switch/applets/album_la.h
Normal file
31
nx/include/switch/applets/album_la.h
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file album_la.h
|
||||
* @brief Wrapper for using the Album LibraryApplet.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
/// Arg type values pushed for the applet input storage, stored as an u8.
|
||||
typedef enum {
|
||||
AlbumLaArg_ShowAlbumFiles = 0, ///< ShowAlbumFiles. Only displays AlbumFiles associated with the title which launched the Album applet, with the filter button disabled.
|
||||
AlbumLaArg_ShowAllAlbumFiles = 1, ///< ShowAllAlbumFiles. Displays all AlbumFiles, with filtering allowed.
|
||||
AlbumLaArg_ShowAllAlbumFilesForHomeMenu = 2, ///< ShowAllAlbumFilesForHomeMenu. Similar to ::AlbumLaArg_ShowAllAlbumFiles.
|
||||
} AlbumLaArg;
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::AlbumLaArg_ShowAlbumFiles and playStartupSound=false.
|
||||
*/
|
||||
Result albumLaShowAlbumFiles(void);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::AlbumLaArg_ShowAllAlbumFiles and playStartupSound=false.
|
||||
*/
|
||||
Result albumLaShowAllAlbumFiles(void);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::AlbumLaArg_ShowAllAlbumFilesForHomeMenu and playStartupSound=true.
|
||||
*/
|
||||
Result albumLaShowAllAlbumFilesForHomeMenu(void);
|
||||
|
||||
94
nx/include/switch/applets/friends_la.h
Normal file
94
nx/include/switch/applets/friends_la.h
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file friends_la.h
|
||||
* @brief Wrapper for using the MyPage (friends) LibraryApplet.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/acc.h"
|
||||
#include "../services/friends.h"
|
||||
|
||||
/// Arg type values used with \ref FriendsLaArg.
|
||||
typedef enum {
|
||||
FriendsLaArgType_ShowFriendList = 0, ///< ShowFriendList. Launches the applet with the "Friend List" menu initially selected.
|
||||
FriendsLaArgType_ShowUserDetailInfo = 1, ///< ShowUserDetailInfo
|
||||
FriendsLaArgType_StartSendingFriendRequest = 2, ///< StartSendingFriendRequest
|
||||
FriendsLaArgType_ShowMethodsOfSendingFriendRequest = 3, ///< ShowMethodsOfSendingFriendRequest. Launches the applet with the "Add Friend" menu initially selected.
|
||||
FriendsLaArgType_StartFacedFriendRequest = 4, ///< StartFacedFriendRequest. Launches the applet where the "Search for Local Users" menu is initially shown. Returning from this menu will exit the applet.
|
||||
FriendsLaArgType_ShowReceivedFriendRequestList = 5, ///< ShowReceivedFriendRequestList. Launches the applet where the "Received Friend Requests" menu is initially shown. Returning from this menu will exit the applet.
|
||||
FriendsLaArgType_ShowBlockedUserList = 6, ///< ShowBlockedUserList. Launches the applet where the "Blocked-User List" menu is initially shown. Returning from this menu will exit the applet.
|
||||
FriendsLaArgType_ShowMyProfile = 7, ///< ShowMyProfile. Launches the applet with the "Profile" menu initially selected. ShowMyProfileForHomeMenu is identical to this except for playStartupSound=true.
|
||||
} FriendsLaArgType;
|
||||
|
||||
/// Arg struct pushed for the applet input storage.
|
||||
/// The fields following the userID are only set for ::FriendsLaArgType_ShowUserDetailInfo/::FriendsLaArgType_StartSendingFriendRequest, for everything else these are cleared.
|
||||
typedef struct {
|
||||
u32 type; ///< \ref FriendsLaArgType
|
||||
u32 pad; ///< Padding.
|
||||
AccountUid userID; ///< \ref AccountUid
|
||||
u64 networkServiceAccountId; ///< NetworkServiceAccountId for the other account.
|
||||
FriendsInAppScreenName first_inAppScreenName; ///< First InAppScreenName.
|
||||
FriendsInAppScreenName second_inAppScreenName; ///< Second InAppScreenName.
|
||||
} FriendsLaArg;
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowFriendList, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowFriendList(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowUserDetailInfo, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
* @param[in] networkServiceAccountId NetworkServiceAccountId for the user to show UserDetailInfo for.
|
||||
* @param[in] first_inAppScreenName First \ref FriendsInAppScreenName.
|
||||
* @param[in] second_inAppScreenName Second \ref FriendsInAppScreenName.
|
||||
*/
|
||||
Result friendsLaShowUserDetailInfo(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_StartSendingFriendRequest, the specified input, and playStartupSound=false. On success, this will load the output Result from the output storage.
|
||||
* @param[in] userID \ref AccountUid
|
||||
* @param[in] networkServiceAccountId NetworkServiceAccountId to send the friend request to.
|
||||
* @param[in] first_inAppScreenName First \ref FriendsInAppScreenName.
|
||||
* @param[in] second_inAppScreenName Second \ref FriendsInAppScreenName.
|
||||
*/
|
||||
Result friendsLaStartSendingFriendRequest(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowMethodsOfSendingFriendRequest, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowMethodsOfSendingFriendRequest(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_StartFacedFriendRequest, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaStartFacedFriendRequest(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowReceivedFriendRequestList, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowReceivedFriendRequestList(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowBlockedUserList, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowBlockedUserList(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Launches the applet with ::FriendsLaArgType_ShowMyProfile, the specified input, and playStartupSound=false.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowMyProfile(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Same as \ref friendsLaShowMyProfile except with playStartupSound=true.
|
||||
* @param[in] userID \ref AccountUid
|
||||
*/
|
||||
Result friendsLaShowMyProfileForHomeMenu(AccountUid *userID);
|
||||
|
||||
@ -197,12 +197,13 @@ typedef struct {
|
||||
s32 unk_x20;
|
||||
s32 unk_x24;
|
||||
u8 returnButtonFlag; ///< Controls whether the Return button is enabled, for newlines input. 0 = disabled, non-zero = enabled.
|
||||
u16 unk_x29;
|
||||
u8 unk_x29;
|
||||
u8 unk_x2a;
|
||||
u8 unk_x2b;
|
||||
u32 flags; ///< Bitmask 0x4: unknown.
|
||||
u8 unk_x30;
|
||||
u8 unk_x31[0x17];
|
||||
} PACKED SwkbdAppearArg;
|
||||
} SwkbdAppearArg;
|
||||
|
||||
typedef struct {
|
||||
u32 unk_x0;
|
||||
@ -226,7 +227,8 @@ typedef struct {
|
||||
u8 disableTouch; ///< Flags bitmask 0x200.
|
||||
u8 disableUSBKeyboard; ///< Flags bitmask 0x800.
|
||||
u8 unk_x468[5];
|
||||
u16 unk_x46d;
|
||||
u8 unk_x46d;
|
||||
u8 unk_x46e;
|
||||
u8 unk_x46f;
|
||||
float keytopScaleX; ///< Flags bitmask 0x200.
|
||||
float keytopScaleY; ///< Flags bitmask 0x200.
|
||||
@ -241,7 +243,7 @@ typedef struct {
|
||||
u8 triggerFlag; ///< [6.0.0+] Enables using the trigger field when set.
|
||||
u8 trigger; ///< [6.0.0+] Trigger
|
||||
u8 pad_x49f;
|
||||
} PACKED SwkbdInlineCalcArg;
|
||||
} SwkbdInlineCalcArg;
|
||||
|
||||
/// Struct data for SwkbdInline Interactive reply storage ChangedString*, at the end following the string.
|
||||
typedef struct {
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "../types.h"
|
||||
#include "../services/applet.h"
|
||||
#include "../services/caps.h"
|
||||
#include "../services/acc.h"
|
||||
|
||||
/// This indicates the type of web-applet.
|
||||
typedef enum {
|
||||
@ -126,7 +127,7 @@ typedef enum {
|
||||
WebArgType_NewsFlag = 0xB, ///< [1.0.0+] u8 bool
|
||||
WebArgType_UnknownC = 0xC, ///< [1.0.0+] u8
|
||||
WebArgType_UnknownD = 0xD, ///< [1.0.0+] u8
|
||||
WebArgType_UserID = 0xE, ///< [1.0.0+] u128 userID, controls which user-specific savedata to mount.
|
||||
WebArgType_Uid = 0xE, ///< [1.0.0+] \ref AccountUid, controls which user-specific savedata to mount.
|
||||
WebArgType_AlbumEntry0 = 0xF, ///< [1.0.0+] Share-applet caps AlbumEntry, entry 0.
|
||||
WebArgType_ScreenShot = 0x10, ///< [1.0.0+] u8 bool
|
||||
WebArgType_EcClientCert = 0x11, ///< [1.0.0+] u8 bool
|
||||
@ -344,9 +345,9 @@ Result webConfigSetWhitelist(WebCommonConfig* config, const char* whitelist);
|
||||
* @note Only available with config created by \ref webPageCreate, \ref webLobbyCreate, or with Share-applet.
|
||||
* @note Used automatically by \ref webShareCreate and \ref webLobbyCreate with userID=0.
|
||||
* @param config WebCommonConfig object.
|
||||
* @param userID Account userID
|
||||
* @param uid \ref AccountUid
|
||||
*/
|
||||
Result webConfigSetUserID(WebCommonConfig* config, u128 userID);
|
||||
Result webConfigSetUid(WebCommonConfig* config, AccountUid *uid);
|
||||
|
||||
/**
|
||||
* @brief Sets the Share CapsAlbumEntry.
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
/// PcmFormat
|
||||
typedef enum {
|
||||
PcmFormat_Invalid = 0,
|
||||
PcmFormat_Int8 = 1,
|
||||
@ -18,6 +19,7 @@ typedef enum {
|
||||
PcmFormat_Adpcm = 6,
|
||||
} PcmFormat;
|
||||
|
||||
/// AudioDeviceName
|
||||
typedef struct {
|
||||
char name[0x100];
|
||||
} AudioDeviceName;
|
||||
|
||||
@ -10,7 +10,7 @@ typedef struct {
|
||||
bool initialized : 1;
|
||||
bool has_transact_auto : 1;
|
||||
s32 id;
|
||||
size_t ipc_buffer_size;
|
||||
size_t dummy;
|
||||
Service* relay;
|
||||
} Binder;
|
||||
|
||||
|
||||
@ -9,6 +9,9 @@
|
||||
#include "../arm/tls.h"
|
||||
#include "../kernel/svc.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
/// IPC input header magic
|
||||
#define SFCI_MAGIC 0x49434653
|
||||
/// IPC output header magic
|
||||
@ -29,13 +32,13 @@ typedef enum {
|
||||
BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory.
|
||||
BufferType_Invalid=2,
|
||||
BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping.
|
||||
} BufferType;
|
||||
} BufferType DEPRECATED;
|
||||
|
||||
typedef enum {
|
||||
BufferDirection_Send=0,
|
||||
BufferDirection_Recv=1,
|
||||
BufferDirection_Exch=2,
|
||||
} BufferDirection;
|
||||
} BufferDirection DEPRECATED;
|
||||
|
||||
typedef enum {
|
||||
IpcCommandType_Invalid = 0,
|
||||
@ -46,13 +49,13 @@ typedef enum {
|
||||
IpcCommandType_Control = 5,
|
||||
IpcCommandType_RequestWithContext = 6,
|
||||
IpcCommandType_ControlWithContext = 7,
|
||||
} IpcCommandType;
|
||||
} IpcCommandType DEPRECATED;
|
||||
|
||||
typedef enum {
|
||||
DomainMessageType_Invalid = 0,
|
||||
DomainMessageType_SendMessage = 1,
|
||||
DomainMessageType_Close = 2,
|
||||
} DomainMessageType;
|
||||
} DomainMessageType DEPRECATED;
|
||||
|
||||
/// IPC domain message header.
|
||||
typedef struct {
|
||||
@ -61,13 +64,13 @@ typedef struct {
|
||||
u16 Length;
|
||||
u32 ThisObjectId;
|
||||
u32 Pad[2];
|
||||
} DomainMessageHeader;
|
||||
} DomainMessageHeader DEPRECATED;
|
||||
|
||||
/// IPC domain response header.
|
||||
typedef struct {
|
||||
u32 NumObjectIds;
|
||||
u32 Pad[3];
|
||||
} DomainResponseHeader;
|
||||
} DomainResponseHeader DEPRECATED;
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -91,12 +94,13 @@ typedef struct {
|
||||
|
||||
size_t NumObjectIds;
|
||||
u32 ObjectIds[IPC_MAX_OBJECTS];
|
||||
} IpcCommand;
|
||||
} IpcCommand DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Initializes an IPC command structure.
|
||||
* @param cmd IPC command structure.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcInitialize(IpcCommand* cmd) {
|
||||
*cmd = (IpcCommand){};
|
||||
}
|
||||
@ -106,19 +110,19 @@ typedef struct {
|
||||
u32 Size; ///< Size of the buffer.
|
||||
u32 Addr; ///< Lower 32-bits of the address of the buffer
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
} IpcBufferDescriptor;
|
||||
} IpcBufferDescriptor DEPRECATED;
|
||||
|
||||
/// IPC static send-buffer descriptor.
|
||||
typedef struct {
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
u32 Addr; ///< Lower 32-bits of the address
|
||||
} IpcStaticSendDescriptor;
|
||||
} IpcStaticSendDescriptor DEPRECATED;
|
||||
|
||||
/// IPC static receive-buffer descriptor.
|
||||
typedef struct {
|
||||
u32 Addr; ///< Lower 32-bits of the address of the buffer
|
||||
u32 Packed; ///< Packed data (including higher bits of the address)
|
||||
} IpcStaticRecvDescriptor;
|
||||
} IpcStaticRecvDescriptor DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Adds a buffer to an IPC command structure.
|
||||
@ -127,6 +131,7 @@ typedef struct {
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend;
|
||||
cmd->Buffers[off] = buffer;
|
||||
@ -142,6 +147,7 @@ static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend + cmd->NumRecv;
|
||||
cmd->Buffers[off] = buffer;
|
||||
@ -157,6 +163,7 @@ static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size,
|
||||
* @param size Size of the buffer.
|
||||
* @param type Buffer type.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
|
||||
size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch;
|
||||
cmd->Buffers[off] = buffer;
|
||||
@ -172,6 +179,7 @@ static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size,
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) {
|
||||
size_t off = cmd->NumStaticIn;
|
||||
cmd->Statics[off] = buffer;
|
||||
@ -187,6 +195,7 @@ static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) {
|
||||
size_t off = cmd->NumStaticIn + cmd->NumStaticOut;
|
||||
cmd->Statics[off] = buffer;
|
||||
@ -203,6 +212,7 @@ static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size,
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size, const void* buffer, size_t size, u8 index) {
|
||||
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
|
||||
ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal);
|
||||
@ -221,6 +231,7 @@ static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size,
|
||||
* @param size Size of the buffer.
|
||||
* @param index Index of buffer.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size, void* buffer, size_t size, u8 index) {
|
||||
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
|
||||
ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal);
|
||||
@ -235,6 +246,7 @@ static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size,
|
||||
* @brief Tags an IPC command structure to send the PID.
|
||||
* @param cmd IPC command structure.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcSendPid(IpcCommand* cmd) {
|
||||
cmd->SendPid = true;
|
||||
}
|
||||
@ -245,6 +257,7 @@ static inline void ipcSendPid(IpcCommand* cmd) {
|
||||
* @param h Handle to send.
|
||||
* @remark The receiving process gets a copy of the handle.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
|
||||
cmd->Handles[cmd->NumHandlesCopy++] = h;
|
||||
}
|
||||
@ -255,6 +268,7 @@ static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
|
||||
* @param h Handle to send.
|
||||
* @remark The sending process loses ownership of the handle, which is transferred to the receiving process.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
|
||||
cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h;
|
||||
}
|
||||
@ -265,6 +279,7 @@ static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
|
||||
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
|
||||
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
size_t i;
|
||||
@ -350,6 +365,7 @@ static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
|
||||
* @param session IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcDispatch(Handle session) {
|
||||
return svcSendSyncRequest(session);
|
||||
}
|
||||
@ -361,8 +377,8 @@ static inline Result ipcDispatch(Handle session) {
|
||||
|
||||
/// IPC parsed command (response) structure.
|
||||
typedef struct {
|
||||
IpcCommandType CommandType; ///< Type of the command
|
||||
|
||||
IpcCommandType CommandType; ///< Type of the command
|
||||
|
||||
bool HasPid; ///< true if the 'Pid' field is filled out.
|
||||
u64 Pid; ///< PID included in the response (only if HasPid is true)
|
||||
|
||||
@ -376,7 +392,7 @@ typedef struct {
|
||||
u32 InThisObjectId; ///< Object ID to call the command on (for domain messages).
|
||||
size_t InNumObjectIds; ///< Number of object IDs (for domain messages).
|
||||
u32 InObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages).
|
||||
|
||||
|
||||
bool IsDomainResponse; ///< true if the the message is a Domain response.
|
||||
size_t OutNumObjectIds; ///< Number of object IDs (for domain responses).
|
||||
u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses).
|
||||
@ -391,25 +407,26 @@ typedef struct {
|
||||
void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics.
|
||||
size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics.
|
||||
u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics.
|
||||
|
||||
|
||||
size_t NumStaticsOut; ///< Number of output statics available in the response.
|
||||
|
||||
void* Raw; ///< Pointer to the raw embedded data structure in the response.
|
||||
void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding.
|
||||
size_t RawSize; ///< Size of the raw embedded data.
|
||||
} IpcParsedCommand;
|
||||
} IpcParsedCommand DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Parse an IPC command response into an IPC parsed command structure.
|
||||
* @param r IPC parsed command structure to fill in.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcParse(IpcParsedCommand* r) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
u32 ctrl0 = *buf++;
|
||||
u32 ctrl1 = *buf++;
|
||||
size_t i;
|
||||
|
||||
|
||||
r->IsDomainRequest = false;
|
||||
r->IsDomainResponse = false;
|
||||
|
||||
@ -417,7 +434,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
|
||||
r->HasPid = false;
|
||||
r->RawSize = (ctrl1 & 0x1ff) * 4;
|
||||
r->NumHandles = 0;
|
||||
|
||||
|
||||
r->NumStaticsOut = (ctrl1 >> 10) & 15;
|
||||
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor
|
||||
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors
|
||||
@ -505,6 +522,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
|
||||
* @param size Output variable in which to store the size.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
@ -544,6 +562,7 @@ static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
|
||||
* @param session IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcCloseSession(Handle session) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
buf[0] = IpcCommandType_Close;
|
||||
@ -558,6 +577,7 @@ static inline Result ipcCloseSession(Handle session) {
|
||||
* @param new_session_out Output cloned IPC session handle.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_session_out) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
@ -603,6 +623,7 @@ static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_sessio
|
||||
* @param object_id_out Output variable in which to store the object ID.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) {
|
||||
u32* buf = (u32*)armGetTls();
|
||||
|
||||
@ -640,6 +661,7 @@ static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_ou
|
||||
* @param cmd IPC domain command structure.
|
||||
* @param object_id Object ID to send.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
|
||||
cmd->ObjectIds[cmd->NumObjectIds++] = object_id;
|
||||
}
|
||||
@ -651,6 +673,7 @@ static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
|
||||
* @param object_id Domain object ID.
|
||||
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) {
|
||||
void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader) + cmd->NumObjectIds*sizeof(u32));
|
||||
DomainMessageHeader* hdr = (DomainMessageHeader*) raw;
|
||||
@ -672,6 +695,7 @@ static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw
|
||||
* @param r IPC parsed command structure to fill in.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
|
||||
Result rc = ipcParse(r);
|
||||
DomainMessageHeader *hdr;
|
||||
@ -710,6 +734,7 @@ static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
|
||||
* @param sizeof_raw Size in bytes of the raw data structure.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) {
|
||||
Result rc = ipcParse(r);
|
||||
DomainResponseHeader *hdr;
|
||||
@ -722,7 +747,7 @@ static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_r
|
||||
object_ids = (u32*)(((uintptr_t) r->Raw) + sizeof_raw);//Official sw doesn't align this.
|
||||
|
||||
r->IsDomainResponse = true;
|
||||
|
||||
|
||||
r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
||||
if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
||||
@ -739,6 +764,7 @@ static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_r
|
||||
* @param object_id ID of the object to close.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
|
||||
IpcCommand c;
|
||||
DomainMessageHeader* hdr;
|
||||
@ -756,3 +782,5 @@ static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
@ -123,6 +123,7 @@ enum {
|
||||
LibnxError_NvinfoFailedToInitialize,
|
||||
LibnxError_NvbufFailedToInitialize,
|
||||
LibnxError_LibAppletBadExit,
|
||||
LibnxError_InvalidCmifOutHeader,
|
||||
};
|
||||
|
||||
/// libnx binder error codes
|
||||
|
||||
@ -49,7 +49,7 @@ int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath);
|
||||
Result fsdevSetArchiveBit(const char *path);
|
||||
|
||||
/// This calls fsFsCreateFile on the filesystem specified by the input path (as used in stdio).
|
||||
Result fsdevCreateFile(const char* path, size_t size, int flags);
|
||||
Result fsdevCreateFile(const char* path, size_t size, u32 flags);
|
||||
|
||||
/// Recursively deletes the directory specified by the input path (as used in stdio).
|
||||
Result fsdevDeleteDirectoryRecursively(const char *path);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/acc.h"
|
||||
|
||||
/// Structure representing an entry in the homebrew environment configuration.
|
||||
typedef struct {
|
||||
@ -114,4 +115,4 @@ bool envHasRandomSeed(void);
|
||||
void envGetRandomSeed(u64 out[2]);
|
||||
|
||||
/// Returns a pointer to the user id storage area (if present).
|
||||
u128* envGetUserIdStorage(void);
|
||||
AccountUid* envGetUserIdStorage(void);
|
||||
|
||||
@ -6,37 +6,60 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
#define ACC_USER_LIST_SIZE 8
|
||||
|
||||
typedef enum {
|
||||
AccountServiceType_NotInitialized = 0, ///< Same as ::AccountServiceType_Application during \ref accountInitialize.
|
||||
AccountServiceType_Application = 1, ///< Initializes acc:u0.
|
||||
AccountServiceType_System = 2, ///< Initializes acc:u1.
|
||||
AccountServiceType_Administrator = 3, ///< Initializes acc:su.
|
||||
} AccountServiceType;
|
||||
|
||||
/// Profile
|
||||
typedef struct {
|
||||
Service s;
|
||||
Service s; ///< IProfile
|
||||
} AccountProfile;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 unk_x0;
|
||||
/// Account UserId.
|
||||
typedef struct {
|
||||
u64 uid[2]; ///< UserId. All-zero is invalid / Uid not set. See also \ref accountUidIsValid.
|
||||
} AccountUid;
|
||||
|
||||
/// UserData
|
||||
typedef struct {
|
||||
u32 unk_x0; ///< Unknown.
|
||||
u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs.
|
||||
u8 iconBackgroundColorID; ///< Profile icon background color ID
|
||||
u8 unk_x9[0x7];
|
||||
u8 unk_x9[0x7]; ///< Unknown.
|
||||
u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used.
|
||||
u8 unk_x20[0x60]; ///< Usually zeros?
|
||||
} PACKED AccountUserData;
|
||||
} AccountUserData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u128 userID;
|
||||
/// ProfileBase
|
||||
typedef struct {
|
||||
AccountUid userID; ///< \ref AccountUid
|
||||
u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit.
|
||||
char username[0x20]; ///< UTF-8 Username.
|
||||
} PACKED AccountProfileBase;
|
||||
char nickname[0x20]; ///< UTF-8 Nickname.
|
||||
} AccountProfileBase;
|
||||
|
||||
/**
|
||||
* @brief Sets the \ref AccountServiceType for initialization. Call this function before \ref accountInitialize, if needed.
|
||||
* @note By default ::AccountServiceType_NotInitialized will be used.
|
||||
*/
|
||||
void accountSetServiceType(AccountServiceType serviceType);
|
||||
|
||||
/// Initialize account.
|
||||
Result accountInitialize(void);
|
||||
|
||||
/// Exit account.
|
||||
void accountExit(void);
|
||||
|
||||
/// Gets the Service object for the actual account service session.
|
||||
Service* accountGetServiceSession(void);
|
||||
|
||||
/// Get the total number of user profiles
|
||||
/// Get the total number of user profiles.
|
||||
Result accountGetUserCount(s32* user_count);
|
||||
|
||||
/**
|
||||
@ -45,26 +68,35 @@ Result accountGetUserCount(s32* user_count);
|
||||
* @param max_userIDs Maximum number of user IDs to return.
|
||||
* @param actual_total The actual total number of user IDs found.
|
||||
*/
|
||||
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total);
|
||||
Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total);
|
||||
|
||||
/// Get the userID for the last opened user. The output userID is only valid when the output account_selected==1.
|
||||
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected);
|
||||
/// Get the userID for the last opened user.
|
||||
Result accountGetLastOpenedUser(AccountUid *userID);
|
||||
|
||||
/// Get an AccountProfile for the specified userID.
|
||||
Result accountGetProfile(AccountProfile* out, u128 userID);
|
||||
Result accountGetProfile(AccountProfile* out, const AccountUid *userID);
|
||||
|
||||
/// Close the AccountProfile.
|
||||
void accountProfileClose(AccountProfile* profile);
|
||||
|
||||
/// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL).
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase);
|
||||
|
||||
/// Get the icon image size.
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size);
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size);
|
||||
|
||||
/// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize.
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size);
|
||||
|
||||
void accountProfileClose(AccountProfile* profile);
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size);
|
||||
|
||||
/// Gets the userID which was selected by the profile-selector applet (if any), prior to launching the currently running Application title.
|
||||
/// This gets the cached PreselectedUser loaded during accountInitialize, when PreselectedUser is available.
|
||||
Result accountGetPreselectedUser(u128 *userID);
|
||||
Result accountGetPreselectedUser(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the specified \ref AccountUid is valid/set (non-zero).
|
||||
* @param[in] Uid \ref AccountUid
|
||||
*/
|
||||
NX_CONSTEXPR bool accountUidIsValid(const AccountUid *Uid) {
|
||||
return Uid->uid[0]!=0 || Uid->uid[1]!=0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
/**
|
||||
* @file apm.h
|
||||
* @brief Performance management (apm) service IPC wrapper. This is used internally by applet with __nx_applet_PerformanceConfiguration, however if you prefer non-init/exit can be used manually.
|
||||
* @brief Performance management (apm) service IPC wrapper. This is used internally by applet with __nx_applet_PerformanceConfiguration, however if you prefer non-init/exit can be used manually. See also: https://switchbrew.org/wiki/PTM_services#apm:am
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// PerformanceMode
|
||||
typedef enum {
|
||||
ApmPerformanceMode_Handheld = 0, ///< Handheld
|
||||
ApmPerformanceMode_Docked = 1, ///< Docked
|
||||
} ApmPerformanceMode;
|
||||
|
||||
/// CpuBoostMode. With \ref appletSetCpuBoostMode, only values 0/1 are available. This allows using higher clock rates.
|
||||
typedef enum {
|
||||
@ -15,9 +21,28 @@ typedef enum {
|
||||
ApmCpuBoostMode_Type2 = 2, ///< Use performance configurations 0x9222000B and 0x9222000C.
|
||||
} ApmCpuBoostMode;
|
||||
|
||||
/// Initialize apm. Used automatically by \ref appletInitialize.
|
||||
Result apmInitialize(void);
|
||||
|
||||
/// Exit apm. Used automatically by \ref appletExit.
|
||||
void apmExit(void);
|
||||
|
||||
/// Gets the Service object for the actual apm service session.
|
||||
Service* apmGetServiceSession(void);
|
||||
|
||||
Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration);
|
||||
Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration);
|
||||
/// Gets the Service object for ISession.
|
||||
Service* apmGetServiceSession_Session(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the PerformanceConfiguration for the specified PerformanceMode.
|
||||
* @param[in] PerformanceMode \ref ApmPerformanceMode
|
||||
* @param[in] PerformanceConfiguration PerformanceConfiguration
|
||||
*/
|
||||
Result apmSetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 PerformanceConfiguration);
|
||||
|
||||
/**
|
||||
* @brief Gets the PerformanceConfiguration for the specified PerformanceMode.
|
||||
* @param[in] PerformanceMode \ref ApmPerformanceMode
|
||||
* @param[out] PerformanceConfiguration PerformanceConfiguration
|
||||
*/
|
||||
Result apmGetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 *PerformanceConfiguration);
|
||||
|
||||
@ -7,12 +7,13 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/apm.h"
|
||||
#include "../services/pdm.h"
|
||||
#include "../services/caps.h"
|
||||
#include "../services/pm.h"
|
||||
#include "../services/fs.h"
|
||||
#include "../services/acc.h"
|
||||
#include "../kernel/tmem.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../nacp.h"
|
||||
@ -740,13 +741,6 @@ Result appletGetCurrentIlluminanceEx(bool *bOverLimit, float *fLux);
|
||||
*/
|
||||
Result appletSetWirelessPriorityMode(AppletWirelessPriorityMode mode);
|
||||
|
||||
/**
|
||||
* @brief Sets whether ::AppletMessage_AlbumImageTaken is enabled.
|
||||
* @note Only available with [7.0.0+].
|
||||
* @param[in] flag Whether to enable the notification.
|
||||
*/
|
||||
Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
|
||||
|
||||
/**
|
||||
* @brief Gets the total time in nanoseconds that the current process was actively running (not suspended), relative to when \ref appletInitialize was last used.
|
||||
* @note Only available with [6.0.0+].
|
||||
@ -754,6 +748,13 @@ Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
|
||||
*/
|
||||
Result appletGetProgramTotalActiveTime(u64 *activeTime);
|
||||
|
||||
/**
|
||||
* @brief Sets whether ::AppletMessage_AlbumImageTaken is enabled.
|
||||
* @note Only available with [7.0.0+].
|
||||
* @param[in] flag Whether to enable the notification.
|
||||
*/
|
||||
Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
|
||||
|
||||
/**
|
||||
* @brief Sets the Application AlbumUserData.
|
||||
* @note Only available with [8.0.0+].
|
||||
@ -1423,13 +1424,13 @@ Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats,
|
||||
/**
|
||||
* @brief Same as \ref appletQueryApplicationPlayStatistics except this gets playstats specific to the input userID.
|
||||
* @note Only available with AppletType_*Application on [6.0.0+].
|
||||
* @param userID userID
|
||||
* @param stats Output \ref PdmApplicationPlayStatistics array.
|
||||
* @param titleIDs Input titleIDs array.
|
||||
* @param count Total entries in the input/output arrays.
|
||||
* @param total_out Total output entries.
|
||||
* @param[in] uid \ref AccountUid
|
||||
* @param[out] stats Output \ref PdmApplicationPlayStatistics array.
|
||||
* @param[in] titleIDs Input titleIDs array.
|
||||
* @param[in] count Total entries in the input/output arrays.
|
||||
* @param[out] total_out Total output entries.
|
||||
*/
|
||||
Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out);
|
||||
Result appletQueryApplicationPlayStatisticsByUid(AccountUid *uid, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out);
|
||||
|
||||
/**
|
||||
* @brief Launches Application title {current_titleID}+programIndex. This will enter an infinite-sleep-loop on success.
|
||||
@ -1476,6 +1477,14 @@ Result appletGetPreviousProgramIndex(s32 *programIndex);
|
||||
*/
|
||||
Result appletGetGpuErrorDetectedSystemEvent(Event *out_event);
|
||||
|
||||
/**
|
||||
* @brief CreateMovieMaker. Do not use this directly, use \ref grcCreateMovieMaker instead.
|
||||
* @note Only available with AppletType_*Application on [5.0.0+].
|
||||
* @param[out] srv_out Output Service for applet IMovieMaker.
|
||||
* @param[in] tmem TransferMemory
|
||||
*/
|
||||
Result appletCreateMovieMaker(Service* srv_out, TransferMemory *tmem);
|
||||
|
||||
/**
|
||||
* @brief Launches the jit-sysmodule when it was not previously launched by this cmd. Returns 0 when it was previously launched.
|
||||
* @note Only available with AppletType_*Application on [5.0.0+].
|
||||
@ -1532,12 +1541,12 @@ Result appletGetHomeButtonWriterLockAccessor(AppletLockAccessor *a);
|
||||
/**
|
||||
* @brief PopRequestLaunchApplicationForDebug
|
||||
* @note Only available with AppletType_SystemApplet on [6.0.0+].
|
||||
* @param[out] userIDs Output array of userIDs.
|
||||
* @param[out] userIDs Output array of \ref AccountUid.
|
||||
* @param[in] count Size of the userID array in entries, must be at least the size stored in state.
|
||||
* @param[out] titleID Output Application titleID.
|
||||
* @param[out] total_out Total output userID entries.
|
||||
*/
|
||||
Result appletPopRequestLaunchApplicationForDebug(u128 *userIDs, s32 count, u64 *titleID, s32 *total_out);
|
||||
Result appletPopRequestLaunchApplicationForDebug(AccountUid *userIDs, s32 count, u64 *titleID, s32 *total_out);
|
||||
|
||||
/**
|
||||
* @brief Launches DevMenu and the dev Overlay-applet. This will enter an infinite-sleep-loop on success.
|
||||
@ -1774,11 +1783,11 @@ Result appletApplicationGetApplicationLaunchRequestInfo(AppletApplication *a, Ap
|
||||
* @brief SetUsers for the Application.
|
||||
* @note Only available on [6.0.0+].
|
||||
* @param a \ref AppletApplication
|
||||
* @param[in] userIDs Input array of userIDs.
|
||||
* @param[in] userIDs Input array of \ref AccountUid.
|
||||
* @param[in] count Size of the userID array in entries, must be <=ACC_USER_LIST_SIZE.
|
||||
* @param[in] flag When this flag is true, this just clears the users_available state flag to 0 and returns.
|
||||
*/
|
||||
Result appletApplicationSetUsers(AppletApplication *a, const u128 *userIDs, s32 count, bool flag);
|
||||
Result appletApplicationSetUsers(AppletApplication *a, const AccountUid *userIDs, s32 count, bool flag);
|
||||
|
||||
/**
|
||||
* @brief CheckRightsEnvironmentAvailable.
|
||||
@ -1801,11 +1810,11 @@ Result appletApplicationGetNsRightsEnvironmentHandle(AppletApplication *a, u64 *
|
||||
* @note Only available on [6.0.0+].
|
||||
* @note qlaunch only uses 1 userID with this.
|
||||
* @param a \ref AppletApplication
|
||||
* @param[out] userIDs Output array of userIDs.
|
||||
* @param[out] userIDs Output array of \ref AccountUid.
|
||||
* @param[in] count Size of the userID array in entries, must be at least the size stored in state.
|
||||
* @param[out] total_out Total output entries.
|
||||
*/
|
||||
Result appletApplicationGetDesirableUids(AppletApplication *a, u128 *userIDs, s32 count, s32 *total_out);
|
||||
Result appletApplicationGetDesirableUids(AppletApplication *a, AccountUid *userIDs, s32 count, s32 *total_out);
|
||||
|
||||
/**
|
||||
* @brief ReportApplicationExitTimeout.
|
||||
@ -2029,12 +2038,12 @@ Result appletUnreserveResourceForMovieOperation(void);
|
||||
/**
|
||||
* @brief Gets an array of userIDs for the MainApplet AvailableUsers.
|
||||
* @note Only available with AppletType_LibraryApplet on [6.0.0+].
|
||||
* @param[out] userIDs Output array of userIDs.
|
||||
* @param[out] userIDs Output array of \ref AccountUid.
|
||||
* @param[in] count Size of the userID array in entries, must be at least ACC_USER_LIST_SIZE.
|
||||
* @param[out] flag When true, this indicates that no users are available.
|
||||
* @param[out] total_out Total output entries. This is -1 when flag is true.
|
||||
*/
|
||||
Result appletGetMainAppletAvailableUsers(u128 *userIDs, s32 count, bool *flag, s32 *total_out);
|
||||
Result appletGetMainAppletAvailableUsers(AccountUid *userIDs, s32 count, bool *flag, s32 *total_out);
|
||||
|
||||
///@}
|
||||
|
||||
@ -2129,7 +2138,7 @@ Result appletBeginToObserveHidInputForDevelop(void);
|
||||
* @param[in] offset Offset within the ThemeStorage.
|
||||
* @param[out] transfer_size Actual read size.
|
||||
*/
|
||||
Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, size_t *transfer_size);
|
||||
Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, u64 *transfer_size);
|
||||
|
||||
/**
|
||||
* @brief Writes the ThemeStorage for the current applet.
|
||||
@ -2201,13 +2210,13 @@ Result appletInvalidateTransitionLayer(void);
|
||||
* @brief Requests to launch the specified Application, with the specified users.
|
||||
* @note Only available on [6.0.0+].
|
||||
* @param[in] titleID Application titleID.
|
||||
* @param[in] userIDs Input array of userIDs.
|
||||
* @param[in] userIDs Input array of \ref AccountUid.
|
||||
* @param[in] total_userIDs Total input userIDs, must be <=ACC_USER_LIST_SIZE.
|
||||
* @param[in] flag Whether to use the specified buffer to create a storage which will be pushed for ::AppletLaunchParameterKind_UserChannel.
|
||||
* @param[in] buffer Buffer containing the above storage data.
|
||||
* @param[in] size Size of the storage buffer.
|
||||
*/
|
||||
Result appletRequestLaunchApplicationWithUserAndArgumentForDebug(u64 titleID, u128 *userIDs, size_t total_userIDs, bool flag, const void* buffer, size_t size);
|
||||
Result appletRequestLaunchApplicationWithUserAndArgumentForDebug(u64 titleID, AccountUid *userIDs, size_t total_userIDs, bool flag, const void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref AppletResourceUsageInfo.
|
||||
@ -2262,8 +2271,8 @@ void appletHook(AppletHookCookie* cookie, AppletHookFn callback, void* param);
|
||||
void appletUnhook(AppletHookCookie* cookie);
|
||||
|
||||
/// These return state which is updated by appletMainLoop() when notifications are received.
|
||||
u8 appletGetOperationMode(void);
|
||||
u32 appletGetPerformanceMode(void);
|
||||
AppletOperationMode appletGetOperationMode(void);
|
||||
ApmPerformanceMode appletGetPerformanceMode(void);
|
||||
AppletFocusState appletGetFocusState(void);
|
||||
|
||||
Result appletSetFocusHandlingMode(AppletFocusHandlingMode mode);
|
||||
|
||||
113
nx/include/switch/services/async.h
Normal file
113
nx/include/switch/services/async.h
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file async.h
|
||||
* @brief NS/NIM IAsync* IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../applets/error.h"
|
||||
#include "../kernel/event.h"
|
||||
|
||||
/// AsyncValue
|
||||
typedef struct {
|
||||
Service s; ///< IAsyncValue
|
||||
Event event; ///< Event with autoclear=false.
|
||||
} AsyncValue;
|
||||
|
||||
/// AsyncResult
|
||||
typedef struct {
|
||||
Service s; ///< IAsyncResult
|
||||
Event event; ///< Event with autoclear=false.
|
||||
} AsyncResult;
|
||||
|
||||
///@name IAsyncValue
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Close a \ref AsyncValue.
|
||||
* @note When the object is initialized, this uses \ref asyncValueCancel then \ref asyncValueWait with timeout=U64_MAX.
|
||||
* @param a \ref AsyncValue
|
||||
*/
|
||||
void asyncValueClose(AsyncValue *a);
|
||||
|
||||
/**
|
||||
* @brief Waits for the async operation to finish using the specified timeout.
|
||||
* @param a \ref AsyncValue
|
||||
* @param[in] timeout Timeout in nanoseconds. U64_MAX for no timeout.
|
||||
*/
|
||||
Result asyncValueWait(AsyncValue *a, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Gets the value size.
|
||||
* @param a \ref AsyncValue
|
||||
* @param[out] size Output size.
|
||||
*/
|
||||
Result asyncValueGetSize(AsyncValue *a, u64 *size);
|
||||
|
||||
/**
|
||||
* @brief Gets the value.
|
||||
* @note Prior to using the cmd, this uses \ref asyncResultWait with timeout=U64_MAX.
|
||||
* @param a \ref AsyncValue
|
||||
* @param[out] buffer Output buffer.
|
||||
* @param[in] size Output buffer size.
|
||||
*/
|
||||
Result asyncValueGet(AsyncValue *a, void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Cancels the async operation.
|
||||
* @note Used automatically by \ref asyncValueClose.
|
||||
* @param a \ref AsyncValue
|
||||
*/
|
||||
Result asyncValueCancel(AsyncValue *a);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref ErrorContext.
|
||||
* @param a \ref AsyncValue
|
||||
* @param[out] context \ref ErrorContext
|
||||
*/
|
||||
Result asyncValueGetErrorContext(AsyncValue *a, ErrorContext *context);
|
||||
|
||||
///@}
|
||||
|
||||
///@name IAsyncResult
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Close a \ref AsyncResult.
|
||||
* @note When the object is initialized, this uses \ref asyncResultCancel then \ref asyncResultWait with timeout=U64_MAX.
|
||||
* @param a \ref AsyncResult
|
||||
*/
|
||||
void asyncResultClose(AsyncResult *a);
|
||||
|
||||
/**
|
||||
* @brief Waits for the async operation to finish using the specified timeout.
|
||||
* @param a \ref AsyncResult
|
||||
* @param[in] timeout Timeout in nanoseconds. U64_MAX for no timeout.
|
||||
*/
|
||||
Result asyncResultWait(AsyncResult *a, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Gets the Result.
|
||||
* @note Prior to using the cmd, this uses \ref asyncResultWait with timeout=U64_MAX.
|
||||
* @param a \ref AsyncResult
|
||||
*/
|
||||
Result asyncResultGet(AsyncResult *a);
|
||||
|
||||
/**
|
||||
* @brief Cancels the async operation.
|
||||
* @note Used automatically by \ref asyncResultClose.
|
||||
* @param a \ref AsyncResult
|
||||
*/
|
||||
Result asyncResultCancel(AsyncResult *a);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref ErrorContext.
|
||||
* @param a \ref AsyncResult
|
||||
* @param[out] context \ref ErrorContext
|
||||
*/
|
||||
Result asyncResultGetErrorContext(AsyncResult *a, ErrorContext *context);
|
||||
|
||||
///@}
|
||||
|
||||
@ -9,12 +9,6 @@
|
||||
#include "../audio/audio.h"
|
||||
#include "../services/sm.h"
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#define AUDREN_CONSTEXPR constexpr
|
||||
#else
|
||||
#define AUDREN_CONSTEXPR static inline
|
||||
#endif
|
||||
|
||||
#define AUDREN_TIMER_FREQ_HZ 200.0f
|
||||
#define AUDREN_TIMER_PERIOD_MS 5.0f
|
||||
#define AUDREN_SAMPLES_PER_FRAME_32KHZ 160
|
||||
@ -287,12 +281,12 @@ static inline u32 audrenGetRevision(void)
|
||||
return g_audrenRevision;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config)
|
||||
NX_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config)
|
||||
{
|
||||
return config->num_effects + 4 * config->num_voices;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config)
|
||||
NX_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config)
|
||||
{
|
||||
size_t size = 0;
|
||||
size += sizeof(AudioRendererUpdateDataHeader);
|
||||
@ -307,7 +301,7 @@ AUDREN_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* confi
|
||||
return size;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config)
|
||||
NX_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config)
|
||||
{
|
||||
size_t size = 0;
|
||||
size += sizeof(AudioRendererUpdateDataHeader);
|
||||
|
||||
@ -7,21 +7,72 @@
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../services/acc.h"
|
||||
|
||||
/// ImageOrientation
|
||||
typedef enum {
|
||||
AlbumImageOrientation_Unknown0 = 0, ///< Unknown. Default.
|
||||
AlbumImageOrientation_Unknown1 = 1, ///< Unknown.
|
||||
AlbumImageOrientation_Unknown2 = 2, ///< Unknown.
|
||||
AlbumImageOrientation_Unknown3 = 3, ///< Unknown.
|
||||
} AlbumImageOrientation;
|
||||
|
||||
/// AlbumReportOption
|
||||
typedef enum {
|
||||
AlbumReportOption_Disable = 0, ///< Don't display the screenshot-taken Overlay-applet notification.
|
||||
AlbumReportOption_Enable = 1, ///< Display the screenshot-taken Overlay notification.
|
||||
} AlbumReportOption;
|
||||
|
||||
/// ContentType
|
||||
typedef enum {
|
||||
CapsContentType_Screenshot = 0, ///< Album screenshots.
|
||||
CapsContentType_Movie = 1, ///< Album videos.
|
||||
CapsContentType_ExtraMovie = 3, ///< Videos recorded by the current Application host title via \ref grcCreateMovieMaker.
|
||||
} CapsContentType;
|
||||
|
||||
/// ScreenShotAttribute
|
||||
typedef struct {
|
||||
u32 unk_x0;
|
||||
u8 unk_x4[0x3c];
|
||||
u32 unk_x0; ///< Always set to 0 by official sw.
|
||||
u32 orientation; ///< \ref AlbumImageOrientation
|
||||
u32 unk_x8; ///< Always set to 0 by official sw.
|
||||
u32 unk_xc; ///< Always set to 1 by official sw.
|
||||
u8 unk_x10[0x30]; ///< Always set to 0 by official sw.
|
||||
} CapsScreenShotAttribute;
|
||||
|
||||
/// AlbumFileDateTime. This corresponds to each field in the Album entry filename, prior to the "-".
|
||||
/// ScreenShotAttributeForApplication. Only unk_x0 is used by official sw.
|
||||
typedef struct {
|
||||
u32 unk_x0; ///< Unknown.
|
||||
u8 unk_x4; ///< Unknown.
|
||||
u8 unk_x5; ///< Unknown.
|
||||
u8 unk_x6; ///< Unknown.
|
||||
u8 pad; ///< Padding.
|
||||
u32 unk_x8; ///< Unknown.
|
||||
u32 unk_xc; ///< Unknown.
|
||||
u32 unk_x10; ///< Unknown.
|
||||
u32 unk_x14; ///< Unknown.
|
||||
u32 unk_x18; ///< Unknown.
|
||||
u32 unk_x1c; ///< Unknown.
|
||||
u16 unk_x20; ///< Unknown.
|
||||
u16 unk_x22; ///< Unknown.
|
||||
u16 unk_x24; ///< Unknown.
|
||||
u16 unk_x26; ///< Unknown.
|
||||
u8 reserved[0x18]; ///< Always zero.
|
||||
} CapsScreenShotAttributeForApplication;
|
||||
|
||||
/// ScreenShotDecodeOption
|
||||
typedef struct {
|
||||
u8 unk_x0[0x20]; ///< Unknown. Set to all-zero by official sw.
|
||||
} CapsScreenShotDecodeOption;
|
||||
|
||||
/// AlbumFileDateTime. This corresponds to each field in the Album entry filename, prior to the "-": "YYYYMMDDHHMMSSII".
|
||||
typedef struct {
|
||||
u16 year; ///< Year.
|
||||
u8 month; ///< Month.
|
||||
u8 day; ///< Day.
|
||||
u8 day; ///< Day of the month.
|
||||
u8 hour; ///< Hour.
|
||||
u8 minute; ///< Minute.
|
||||
u8 second; ///< Second.
|
||||
u8 unk_x7; ///< Unknown.
|
||||
u8 id; ///< Unique ID for when there's multiple Album files with the same timestamp.
|
||||
} CapsAlbumFileDateTime;
|
||||
|
||||
/// AlbumEntryId
|
||||
@ -35,20 +86,79 @@ typedef struct {
|
||||
|
||||
/// AlbumEntry
|
||||
typedef struct {
|
||||
u8 unk_x0[0x8];
|
||||
CapsAlbumEntryId id;
|
||||
u8 unk_x0[0x8]; ///< Unknown.
|
||||
CapsAlbumEntryId id; ///< \ref CapsAlbumEntryId
|
||||
} CapsAlbumEntry;
|
||||
|
||||
/// ApplicationAlbumEntry
|
||||
typedef struct {
|
||||
u8 unk_x0[0x20];
|
||||
union {
|
||||
u8 data[0x20]; ///< Data.
|
||||
|
||||
struct {
|
||||
u8 unk_x0[0x20]; ///< Unknown.
|
||||
} v0; ///< Pre-7.0.0
|
||||
|
||||
struct {
|
||||
u8 unk_x0[0x8]; ///< Unknown.
|
||||
u8 unk_x8[0x8]; ///< Unknown.
|
||||
CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
|
||||
u8 unk_x18[0x8]; ///< Unknown.
|
||||
} v1; ///< [7.0.0+]
|
||||
};
|
||||
} CapsApplicationAlbumEntry;
|
||||
|
||||
/// ImageOrientation
|
||||
typedef enum {
|
||||
AlbumImageOrientation_Unknown0 = 0, ///< Unknown.
|
||||
AlbumImageOrientation_Unknown1 = 1, ///< Unknown.
|
||||
AlbumImageOrientation_Unknown2 = 2, ///< Unknown.
|
||||
AlbumImageOrientation_Unknown3 = 3, ///< Unknown.
|
||||
} AlbumImageOrientation;
|
||||
/// ApplicationAlbumFileEntry
|
||||
typedef struct {
|
||||
CapsApplicationAlbumEntry entry; ///< \ref CapsApplicationAlbumEntry
|
||||
CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
|
||||
u64 unk_x28; ///< Unknown.
|
||||
} CapsApplicationAlbumFileEntry;
|
||||
|
||||
/// ApplicationData
|
||||
typedef struct {
|
||||
u8 userdata[0x400]; ///< UserData.
|
||||
u32 size; ///< UserData size.
|
||||
} CapsApplicationData;
|
||||
|
||||
/// UserIdList
|
||||
typedef struct {
|
||||
AccountUid userIDs[ACC_USER_LIST_SIZE]; ///< \ref AccountUid
|
||||
u8 count; ///< Total userIDs.
|
||||
u8 pad[7]; ///< Padding.
|
||||
} CapsUserIdList;
|
||||
|
||||
/// LoadAlbumScreenShotImageOutputForApplication
|
||||
typedef struct {
|
||||
s64 width; ///< Width. Official sw copies this to a s32 output field.
|
||||
s64 height; ///< Height. Official sw copies this to a s32 output field.
|
||||
CapsScreenShotAttributeForApplication attr; ///< \ref CapsScreenShotAttributeForApplication
|
||||
CapsApplicationData appdata; ///< \ref CapsApplicationData
|
||||
u8 reserved[0xac]; ///< Unused.
|
||||
} CapsLoadAlbumScreenShotImageOutputForApplication;
|
||||
|
||||
/// Gets the ShimLibraryVersion.
|
||||
u64 capsGetShimLibraryVersion(void);
|
||||
|
||||
/// Gets the default start_datetime.
|
||||
static inline CapsAlbumFileDateTime capsGetDefaultStartDateTime(void) {
|
||||
return (CapsAlbumFileDateTime){.year = 1970, .month = 1, .day = 1};
|
||||
}
|
||||
|
||||
/// Gets the default end_datetime.
|
||||
static inline CapsAlbumFileDateTime capsGetDefaultEndDateTime(void) {
|
||||
return (CapsAlbumFileDateTime){.year = 3000, .month = 1, .day = 1};
|
||||
}
|
||||
|
||||
/// Convert a \ref CapsApplicationAlbumFileEntry to \ref CapsApplicationAlbumEntry.
|
||||
static inline void capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry(CapsApplicationAlbumEntry *out, CapsApplicationAlbumFileEntry *in) {
|
||||
*out = in->entry;
|
||||
}
|
||||
|
||||
/// Convert a \ref CapsApplicationAlbumEntry to \ref CapsApplicationAlbumFileEntry. Should only be used on [7.0.0+].
|
||||
static inline void capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry(CapsApplicationAlbumFileEntry *out, CapsApplicationAlbumEntry *in) {
|
||||
out->entry = *in;
|
||||
out->datetime = in->v1.datetime;
|
||||
out->unk_x28 = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -6,12 +6,16 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/caps.h"
|
||||
|
||||
/// Initialize caps:sc. Only available on [2.0.0+].
|
||||
Result capsscInitialize(void);
|
||||
|
||||
/// Exit caps:sc.
|
||||
void capsscExit(void);
|
||||
|
||||
/// Gets the Service for caps:sc.
|
||||
Service* capsscGetServiceSession(void);
|
||||
|
||||
/**
|
||||
@ -27,5 +31,5 @@ Service* capsscGetServiceSession(void);
|
||||
* @param buffer_index Starting image buffer index. Must be < buffer_count.
|
||||
* @param timeout Timeout in nanoseconds. A default value of 100000000 can be used.
|
||||
*/
|
||||
Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout);
|
||||
Result capsscCaptureRawImageWithTimeout(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout);
|
||||
|
||||
|
||||
@ -6,17 +6,89 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/acc.h"
|
||||
#include "../services/caps.h"
|
||||
|
||||
/// Initialize caps:su. Only available on [4.0.0+].
|
||||
Result capssuInitialize(void);
|
||||
|
||||
/// Exit caps:su.
|
||||
void capssuExit(void);
|
||||
|
||||
/// Gets the Service for caps:su.
|
||||
Service* capssuGetServiceSession(void);
|
||||
|
||||
/// Same as \ref capssuSaveScreenShotEx0, except this uses an all-zero CapsScreenShotAttribute where the first u32 is set to attr_val. attr_val can be zero.
|
||||
Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out);
|
||||
/**
|
||||
* @brief This is a wrapper for \ref capssuSaveScreenShotEx0.
|
||||
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
|
||||
* @param[in] buffer RGBA8 1280x720 image buffer.
|
||||
* @param[in] size Size of the buffer.
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[in] orientation \ref AlbumImageOrientation
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShot(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, CapsApplicationAlbumEntry *out);
|
||||
|
||||
/// Saves an Album screenshot using the specified gfx data in buffer (1280x720 RGBA8), size must be at least 0x384000. unk can be zero.
|
||||
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out);
|
||||
/**
|
||||
* @brief Similar to \ref capssuSaveScreenShot, except this is a wrapper for \ref capssuSaveScreenShotEx1.
|
||||
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
|
||||
* @note Only available on [8.0.0+].
|
||||
* @param[in] buffer RGBA8 1280x720 image data buffer.
|
||||
* @param[in] size Size of the buffer.
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[in] orientation \ref AlbumImageOrientation
|
||||
* @param[in] userdata Input UserData buffer. If NULL, the \ref CapsApplicationData will be empty.
|
||||
* @param[in] userdata_size Input UserData size, must be within bounds for CapsApplicationData::userdata. If 0, the \ref CapsApplicationData will be empty.
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShotWithUserData(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const void* userdata, size_t userdata_size, CapsApplicationAlbumEntry *out);
|
||||
|
||||
/**
|
||||
* @brief Similar to \ref capssuSaveScreenShot, except this is a wrapper for \ref capssuSaveScreenShotEx2.
|
||||
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
|
||||
* @note Only available on [6.0.0+].
|
||||
* @param[in] buffer RGBA8 1280x720 image data buffer.
|
||||
* @param[in] size Size of the buffer.
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[in] orientation \ref AlbumImageOrientation
|
||||
* @param[in] userIDs Input array of \ref AccountUid. If NULL, the \ref CapsUserIdList will be empty.
|
||||
* @param[in] userID_count Size of the userID array in entries, must be within bounds for CapsUserIdList::userIDs. If 0, the \ref CapsUserIdList will be empty.
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShotWithUserIds(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const AccountUid* userIDs, size_t userID_count, CapsApplicationAlbumEntry *out);
|
||||
|
||||
/**
|
||||
* @brief Saves an Album screenshot using the specified gfx data in the buffer, with the specified \ref CapsScreenShotAttribute.
|
||||
* @param[in] buffer RGBA8 1280x720 image data buffer.
|
||||
* @param[in] size Size of the buffer, must be at least 0x384000.
|
||||
* @param[in] attr \ref CapsScreenShotAttribute
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out);
|
||||
|
||||
/**
|
||||
* @brief Same as \ref capssuSaveScreenShotEx0, except this allows specifying the \ref CapsApplicationData.
|
||||
* @note Only available on [8.0.0+].
|
||||
* @param[in] buffer RGBA8 1280x720 image data buffer.
|
||||
* @param[in] size Size of the buffer, must be at least 0x384000.
|
||||
* @param[in] attr \ref CapsScreenShotAttribute
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[in] appdata \ref CapsApplicationData
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationData *appdata, CapsApplicationAlbumEntry *out);
|
||||
|
||||
/**
|
||||
* @brief Same as \ref capssuSaveScreenShotEx0, except this allows specifying the \ref CapsUserIdList.
|
||||
* @note Only available on [6.0.0+].
|
||||
* @param[in] buffer RGBA8 1280x720 image data buffer.
|
||||
* @param[in] size Size of the buffer, must be at least 0x384000.
|
||||
* @param[in] attr \ref CapsScreenShotAttribute
|
||||
* @param[in] reportoption \ref AlbumReportOption
|
||||
* @param[in] list \ref CapsUserIdList
|
||||
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
|
||||
*/
|
||||
Result capssuSaveScreenShotEx2(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsUserIdList *list, CapsApplicationAlbumEntry *out);
|
||||
|
||||
|
||||
173
nx/include/switch/services/capsu.h
Normal file
173
nx/include/switch/services/capsu.h
Normal file
@ -0,0 +1,173 @@
|
||||
/**
|
||||
* @file capsu.h
|
||||
* @brief Application Album (caps:u) service IPC wrapper.
|
||||
* This is only usable with AlbumFiles associated with the current Application host title.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/caps.h"
|
||||
#include "../services/acc.h"
|
||||
|
||||
/// Initialize caps:u. Only available on [5.0.0+].
|
||||
Result capsuInitialize(void);
|
||||
|
||||
/// Exit caps:u.
|
||||
void capsuExit(void);
|
||||
|
||||
/// Gets the Service for caps:u.
|
||||
Service* capsuGetServiceSession(void);
|
||||
|
||||
/// Gets the Service for IAlbumAccessorApplicationSession, only initialized after \ref capsuOpenAlbumMovieStream was used (unaffected by using \ref capsuCloseAlbumMovieStream).
|
||||
Service* capsuGetServiceSession_Accessor(void);
|
||||
|
||||
/**
|
||||
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry.
|
||||
* @note On [6.0.0+] this uses GetAlbumFileList1AafeAruidDeprecated, otherwise this uses GetAlbumFileList0AafeAruidDeprecated.
|
||||
* @note This is an old version of \ref capsuGetAlbumFileList3.
|
||||
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
|
||||
* @param[in] count Max size of the output array in entries.
|
||||
* @param[in] type \ref CapsContentType
|
||||
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[out] total_entries Total output entries.
|
||||
*/
|
||||
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries);
|
||||
|
||||
/**
|
||||
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
|
||||
* @note Only available on [6.0.0+].
|
||||
* @note This is an old version of \ref capsuGetAlbumFileList4.
|
||||
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
|
||||
* @param[in] count Max size of the output array in entries.
|
||||
* @param[in] type \ref CapsContentType
|
||||
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] userID \ref AccountUid
|
||||
* @param[out] total_entries Total output entries.
|
||||
*/
|
||||
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries);
|
||||
|
||||
/**
|
||||
* @brief Gets a listing of \ref CapsApplicationAlbumEntry.
|
||||
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated1 instead.
|
||||
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
|
||||
* @param[in] count Max size of the output array in entries.
|
||||
* @param[in] type \ref CapsContentType
|
||||
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[out] total_entries Total output entries.
|
||||
*/
|
||||
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries);
|
||||
|
||||
/**
|
||||
* @brief Gets a listing of \ref CapsApplicationAlbumEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
|
||||
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated2 instead.
|
||||
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
|
||||
* @param[in] count Max size of the output array in entries.
|
||||
* @param[in] type \ref CapsContentType
|
||||
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
|
||||
* @param[in] userID \ref AccountUid
|
||||
* @param[out] total_entries Total output entries.
|
||||
*/
|
||||
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries);
|
||||
|
||||
/**
|
||||
* @brief Deletes the specified AlbumFile.
|
||||
* @param[in] type \ref CapsContentType, must match ::CapsContentType_ExtraMovie.
|
||||
* @param[in] entry \ref CapsApplicationAlbumFileEntry
|
||||
*/
|
||||
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry);
|
||||
|
||||
/**
|
||||
* @brief Gets the filesize for the entire specified AlbumFile.
|
||||
* @param[in] entry \ref CapsApplicationAlbumFileEntry
|
||||
* @param[out] size Output filesize.
|
||||
*/
|
||||
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size);
|
||||
|
||||
/**
|
||||
* @brief Load the ScreenShotImage for the specified AlbumFile.
|
||||
* @param[out] width Output image width. Optional, can be NULL.
|
||||
* @param[out] height Output image height. Optional, can be NULL.
|
||||
* @param[out] attr \ref CapsScreenShotAttributeForApplication
|
||||
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
|
||||
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
|
||||
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
|
||||
* @param[out] image RGBA8 image output buffer.
|
||||
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 1280x720.
|
||||
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
|
||||
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
|
||||
* @param[in] entry \ref CapsApplicationAlbumFileEntry
|
||||
* @param[in] option \ref CapsScreenShotDecodeOption
|
||||
*/
|
||||
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
|
||||
|
||||
/**
|
||||
* @brief Load the ScreenShotThumbnailImage for the specified AlbumFile.
|
||||
* @param[out] width Output image width. Optional, can be NULL.
|
||||
* @param[out] height Output image height. Optional, can be NULL.
|
||||
* @param[out] attr \ref CapsScreenShotAttributeForApplication
|
||||
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
|
||||
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
|
||||
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
|
||||
* @param[out] image RGBA8 image output buffer.
|
||||
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 320x180.
|
||||
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
|
||||
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
|
||||
* @param[in] entry \ref CapsApplicationAlbumFileEntry
|
||||
* @param[in] option \ref CapsScreenShotDecodeOption
|
||||
*/
|
||||
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
|
||||
|
||||
/**
|
||||
* @brief PrecheckToCreateContents. Official sw only uses this with ::CapsContentType_ExtraMovie.
|
||||
* @param[in] type \ref CapsContentType
|
||||
* @param[in] unk Unknown.
|
||||
*/
|
||||
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk);
|
||||
|
||||
/**
|
||||
* @brief Opens an AlbumMovieStream.
|
||||
* @note This opens IAlbumAccessorApplicationSession if not previously opened, it's closed during \ref capsuExit.
|
||||
* @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 CapsApplicationAlbumFileEntry.
|
||||
* @param[out] stream Stream handle.
|
||||
* @param[in] entry \ref CapsApplicationAlbumFileEntry
|
||||
*/
|
||||
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry);
|
||||
|
||||
/**
|
||||
* @brief Closes an AlbumMovieStream.
|
||||
* @param[in] stream Stream handle.
|
||||
*/
|
||||
Result capsuCloseAlbumMovieStream(u64 stream);
|
||||
|
||||
/**
|
||||
* @brief Gets the data size of an AlbumMovieStream.
|
||||
* @param[in] stream Stream handle.
|
||||
* @param[out] size Size of the actual MP4, without the JPEG at the end.
|
||||
*/
|
||||
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size);
|
||||
|
||||
/**
|
||||
* @brief Reads data from an AlbumMovieStream.
|
||||
* @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 capsuGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size.
|
||||
* @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 capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size);
|
||||
|
||||
/**
|
||||
* @brief Gets the BrokenReason for an AlbumMovieStream.
|
||||
* @note Official sw doesn't use this.
|
||||
* @param[in] stream Stream handle.
|
||||
*/
|
||||
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
Result csrngInitialize(void);
|
||||
void csrngExit(void);
|
||||
|
||||
16
nx/include/switch/services/friends.h
Normal file
16
nx/include/switch/services/friends.h
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @file friend.h
|
||||
* @brief Friends (friend:*) service IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
|
||||
/// InAppScreenName
|
||||
typedef struct {
|
||||
char name[0x40]; ///< UTF-8 string, NUL-terminated.
|
||||
u64 languageCode; ///< LanguageCode, see set.h.
|
||||
} FriendsInAppScreenName;
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../services/acc.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
// We use wrapped handles for type safety.
|
||||
|
||||
@ -17,9 +19,6 @@
|
||||
/// For use with FsSave.
|
||||
#define FS_SAVEDATA_CURRENT_TITLEID 0
|
||||
|
||||
/// For use with \ref FsSave and \ref FsSaveDataInfo.
|
||||
#define FS_SAVEDATA_USERID_COMMONSAVE 0
|
||||
|
||||
typedef struct {
|
||||
u8 c[0x10];
|
||||
} FsRightsId;
|
||||
@ -57,7 +56,7 @@ typedef struct
|
||||
{
|
||||
char name[FS_MAX_PATH]; ///< Entry name.
|
||||
u8 pad[3];
|
||||
s8 type; ///< See FsEntryType.
|
||||
s8 type; ///< See FsDirEntryType.
|
||||
u8 pad2[3]; ///< ?
|
||||
u64 fileSize; ///< File size.
|
||||
} FsDirectoryEntry;
|
||||
@ -66,7 +65,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID.
|
||||
union { u128 userID; } PACKED; ///< userID of the user-specific savedata to access, otherwise FS_SAVEDATA_USERID_COMMONSAVE. See account.h.
|
||||
AccountUid userID; ///< \ref AccountUid for the user-specific savedata to access, otherwise 0 for common savedata.
|
||||
u64 saveID; ///< saveID, 0 for SaveData.
|
||||
u8 saveDataType; ///< See \ref FsSaveDataType.
|
||||
u8 rank; ///< Save data 'rank' or 'precedence'. 0 if this save data is considered the primary save data. 1 if it's considered the secondary save data.
|
||||
@ -108,7 +107,7 @@ typedef struct
|
||||
u8 saveDataSpaceId; ///< See \ref FsSaveDataSpaceId.
|
||||
u8 saveDataType; ///< See \ref FsSaveDataType.
|
||||
u8 pad[6]; ///< Padding.
|
||||
u128 userID; ///< See userID for \ref FsSave.
|
||||
AccountUid userID; ///< FsSave::userID
|
||||
u64 saveID; ///< See saveID for \ref FsSave.
|
||||
u64 titleID; ///< titleID for FsSaveDataType_SaveData.
|
||||
u64 size; ///< Raw saveimage size.
|
||||
@ -126,57 +125,62 @@ typedef struct
|
||||
u8 padding[7];
|
||||
} FsTimeStampRaw;
|
||||
|
||||
/// Returned by fsFsGetEntryType.
|
||||
typedef enum {
|
||||
ENTRYTYPE_DIR = 0,
|
||||
ENTRYTYPE_FILE = 1,
|
||||
} FsEntryType;
|
||||
FsDirEntryType_Dir = 0, ///< Entry is a directory.
|
||||
FsDirEntryType_File = 1, ///< Entry is a file.
|
||||
} FsDirEntryType;
|
||||
|
||||
/// For use with fsFsOpenFile.
|
||||
typedef enum
|
||||
{
|
||||
FS_OPEN_READ = BIT(0), ///< Open for reading.
|
||||
FS_OPEN_WRITE = BIT(1), ///< Open for writing.
|
||||
FS_OPEN_APPEND = BIT(2), ///< Append file.
|
||||
} FsFileFlags;
|
||||
FsOpenMode_Read = BIT(0), ///< Open for reading.
|
||||
FsOpenMode_Write = BIT(1), ///< Open for writing.
|
||||
FsOpenMode_Append = BIT(2), ///< Append file.
|
||||
} FsOpenMode;
|
||||
|
||||
/// For use with fsFsCreateFile.
|
||||
typedef enum
|
||||
{
|
||||
FS_CREATE_BIG_FILE = BIT(0), ///< Creates a ConcatenationFile (dir with archive bit) instead of file.
|
||||
} FsFileCreateFlags;
|
||||
FsCreateOption_BigFile = BIT(0), ///< Creates a ConcatenationFile (dir with archive bit) instead of file.
|
||||
} FsCreateOption;
|
||||
|
||||
/// For use with fsFsOpenDirectory.
|
||||
typedef enum
|
||||
{
|
||||
FS_DIROPEN_DIRECTORY = BIT(0), ///< Enable reading directory entries.
|
||||
FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries.
|
||||
FS_DIROPEN_NO_FILE_SIZE = BIT(31), ///< Causes result entries to not contain filesize information (always 0).
|
||||
} FsDirectoryFlags;
|
||||
FsDirOpenMode_ReadDirs = BIT(0), ///< Enable reading directory entries.
|
||||
FsDirOpenMode_ReadFiles = BIT(1), ///< Enable reading file entries.
|
||||
FsDirOpenMode_NoFileSize = BIT(31), ///< Causes result entries to not contain filesize information (always 0).
|
||||
} FsDirOpenMode;
|
||||
|
||||
/// For use with fsFileRead.
|
||||
typedef enum
|
||||
{
|
||||
FS_READOPTION_NONE = 0, ///< No Option.
|
||||
FsReadOption_None = 0, ///< No option.
|
||||
} FsReadOption;
|
||||
|
||||
/// For use with fsFileWrite.
|
||||
typedef enum
|
||||
{
|
||||
FS_WRITEOPTION_NONE = 0, ///< No option.
|
||||
FS_WRITEOPTION_FLUSH = BIT(0), ///< Forces a flush after write.
|
||||
FsWriteOption_None = 0, ///< No option.
|
||||
FsWriteOption_Flush = BIT(0), ///< Forces a flush after write.
|
||||
} FsWriteOption;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FsStorageId_None = 0,
|
||||
FsStorageId_Host = 1,
|
||||
FsStorageId_GameCard = 2,
|
||||
FsStorageId_NandSystem = 3,
|
||||
FsStorageId_NandUser = 4,
|
||||
FsStorageId_SdCard = 5,
|
||||
/// StorageId
|
||||
typedef enum {
|
||||
FsStorageId_None = 0, ///< None
|
||||
FsStorageId_Host = 1, ///< Host
|
||||
FsStorageId_GameCard = 2, ///< GameCard
|
||||
FsStorageId_NandSystem = 3, ///< NandSystem
|
||||
FsStorageId_NandUser = 4, ///< NandUser
|
||||
FsStorageId_SdCard = 5, ///< SdCard
|
||||
} FsStorageId;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FS_CONTENTSTORAGEID_NandSystem = 0,
|
||||
FS_CONTENTSTORAGEID_NandUser = 1,
|
||||
FS_CONTENTSTORAGEID_SdCard = 2,
|
||||
FsContentStorageId_NandSystem = 0,
|
||||
FsContentStorageId_NandUser = 1,
|
||||
FsContentStorageId_SdCard = 2,
|
||||
} FsContentStorageId;
|
||||
|
||||
typedef enum
|
||||
@ -213,9 +217,9 @@ typedef enum {
|
||||
} FsSaveDataFlags;
|
||||
|
||||
typedef enum {
|
||||
FsGameCardAttribute_AutoBoot = (1 << 0), ///< Causes the cartridge to automatically start on bootup
|
||||
FsGameCardAttribute_ForceError = (1 << 1), ///< Causes NS to throw an error on attempt to load the cartridge
|
||||
FsGameCardAttribute_Repair = (1 << 2), ///< Indicates that this gamecard is a repair tool.
|
||||
FsGameCardAttribute_AutoBoot = BIT(0), ///< Causes the cartridge to automatically start on bootup
|
||||
FsGameCardAttribute_ForceError = BIT(1), ///< Causes NS to throw an error on attempt to load the cartridge
|
||||
FsGameCardAttribute_Repair = BIT(2), ///< Indicates that this gamecard is a repair tool.
|
||||
} FsGameCardAttribute;
|
||||
|
||||
typedef enum {
|
||||
@ -262,11 +266,20 @@ typedef enum {
|
||||
FsBisStorageId_SystemProperPartition = 33,
|
||||
} FsBisStorageId;
|
||||
|
||||
typedef enum {
|
||||
FsPriority_Normal = 0,
|
||||
FsPriority_Realtime = 1,
|
||||
FsPriority_Low = 2,
|
||||
FsPriority_Background = 3,
|
||||
} FsPriority;
|
||||
|
||||
Result fsInitialize(void);
|
||||
void fsExit(void);
|
||||
|
||||
Service* fsGetServiceSession(void);
|
||||
|
||||
void fsSetPriority(FsPriority prio);
|
||||
|
||||
Result fsOpenBisStorage(FsStorage* out, FsBisStorageId partitionId);
|
||||
Result fsOpenBisFileSystem(FsFileSystem* out, FsBisStorageId partitionId, const char* string);
|
||||
|
||||
@ -283,9 +296,9 @@ Result fsExtendSaveDataFileSystem(FsSaveDataSpaceId saveDataSpaceId, u64 saveID,
|
||||
/// Do not call this directly, see fs_dev.h.
|
||||
Result fsMountSdcard(FsFileSystem* out);
|
||||
|
||||
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save);
|
||||
Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save);
|
||||
Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 saveDataSpaceId);
|
||||
Result fsMountSaveData(FsFileSystem* out, u8 inval, const FsSave *save);
|
||||
Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, const FsSave *save);
|
||||
Result fsOpenSaveDataIterator(FsSaveDataIterator* out, FsSaveDataSpaceId saveDataSpaceId);
|
||||
Result fsOpenContentStorageFileSystem(FsFileSystem* out, FsContentStorageId content_storage_id);
|
||||
Result fsOpenCustomStorageFileSystem(FsFileSystem* out, FsCustomStorageId custom_storage_id); /// [7.0.0+]
|
||||
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
|
||||
@ -306,14 +319,14 @@ Result fsGetGlobalAccessLogMode(u32* out_mode);
|
||||
// todo: Rest of commands here
|
||||
|
||||
// Wrapper(s) for fsCreateSaveDataFileSystemBySystemSaveDataId.
|
||||
Result fsCreate_SystemSaveDataWithOwner(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u128 userID, u64 ownerId, u64 size, u64 journalSize, u32 flags);
|
||||
Result fsCreate_SystemSaveDataWithOwner(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, AccountUid *userID, u64 ownerId, u64 size, u64 journalSize, u32 flags);
|
||||
Result fsCreate_SystemSaveData(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u64 size, u64 journalSize, u32 flags);
|
||||
|
||||
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h.
|
||||
|
||||
/// Wrapper(s) for fsMountSaveData.
|
||||
/// See FsSave for titleID and userID.
|
||||
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID);
|
||||
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, AccountUid *userID);
|
||||
|
||||
/// Wrapper for fsMountSystemSaveData.
|
||||
/// WARNING: You can brick when writing to SystemSaveData, if the data is corrupted etc.
|
||||
@ -340,16 +353,16 @@ Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType f
|
||||
Result fsOpenFileSystemWithPatch(FsFileSystem* out, u64 titleId, FsFileSystemType fsType); /// [2.0.0+], like OpenFileSystemWithId but without content path.
|
||||
|
||||
// IFileSystem
|
||||
Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags);
|
||||
Result fsFsCreateFile(FsFileSystem* fs, const char* path, u64 size, u32 option);
|
||||
Result fsFsDeleteFile(FsFileSystem* fs, const char* path);
|
||||
Result fsFsCreateDirectory(FsFileSystem* fs, const char* path);
|
||||
Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path);
|
||||
Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path);
|
||||
Result fsFsRenameFile(FsFileSystem* fs, const char* cur_path, const char* new_path);
|
||||
Result fsFsRenameDirectory(FsFileSystem* fs, const char* cur_path, const char* new_path);
|
||||
Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out);
|
||||
Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out);
|
||||
Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* out);
|
||||
Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsDirEntryType* out);
|
||||
Result fsFsOpenFile(FsFileSystem* fs, const char* path, u32 mode, FsFile* out);
|
||||
Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, u32 mode, FsDir* out);
|
||||
Result fsFsCommit(FsFileSystem* fs);
|
||||
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out);
|
||||
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out);
|
||||
@ -363,36 +376,36 @@ void fsFsClose(FsFileSystem* fs);
|
||||
Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path);
|
||||
|
||||
// IFile
|
||||
Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, u32 option, size_t* out);
|
||||
Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len, u32 option);
|
||||
Result fsFileRead(FsFile* f, u64 off, void* buf, u64 read_size, u32 option, u64* bytes_read);
|
||||
Result fsFileWrite(FsFile* f, u64 off, const void* buf, u64 write_size, u32 option);
|
||||
Result fsFileFlush(FsFile* f);
|
||||
Result fsFileSetSize(FsFile* f, u64 sz);
|
||||
Result fsFileGetSize(FsFile* f, u64* out);
|
||||
Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); /// [4.0.0+]
|
||||
Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, u64 len, FsRangeInfo* out); /// [4.0.0+]
|
||||
void fsFileClose(FsFile* f);
|
||||
|
||||
// IDirectory
|
||||
Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf);
|
||||
Result fsDirRead(FsDir* d, u64 inval, u64* total_entries, size_t max_entries, FsDirectoryEntry *buf);
|
||||
Result fsDirGetEntryCount(FsDir* d, u64* count);
|
||||
void fsDirClose(FsDir* d);
|
||||
|
||||
// IStorage
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
|
||||
Result fsStorageWrite(FsStorage* s, u64 off, const void* buf, size_t len);
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, u64 read_size);
|
||||
Result fsStorageWrite(FsStorage* s, u64 off, const void* buf, u64 write_size);
|
||||
Result fsStorageFlush(FsStorage* s);
|
||||
Result fsStorageSetSize(FsStorage* s, u64 sz);
|
||||
Result fsStorageGetSize(FsStorage* s, u64* out);
|
||||
Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); /// [4.0.0+]
|
||||
Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, u64 len, FsRangeInfo* out); /// [4.0.0+]
|
||||
void fsStorageClose(FsStorage* s);
|
||||
|
||||
// ISaveDataInfoReader
|
||||
|
||||
/// Read FsSaveDataInfo data into the buf array.
|
||||
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries);
|
||||
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, u64* total_entries);
|
||||
void fsSaveDataIteratorClose(FsSaveDataIterator *s);
|
||||
|
||||
// IEventNotifier
|
||||
Result fsEventNotifierGetEventHandle(FsEventNotifier* e, Handle* out);
|
||||
Result fsEventNotifierGetEventHandle(FsEventNotifier* e, Event* out, bool autoclear);
|
||||
void fsEventNotifierClose(FsEventNotifier* e);
|
||||
|
||||
// IDeviceOperator
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/fs.h"
|
||||
|
||||
Result fsldrInitialize(void);
|
||||
@ -15,4 +15,4 @@ Service* fsldrGetServiceSession(void);
|
||||
|
||||
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out);
|
||||
Result fsldrIsArchivedProgram(u64 pid, bool *out);
|
||||
Result fsldrSetCurrentProcess(void);
|
||||
Result fsldrSetCurrentProcess(void);
|
||||
|
||||
@ -10,18 +10,7 @@
|
||||
#include "../services/caps.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../kernel/tmem.h"
|
||||
|
||||
/// GameMovieTrimmer
|
||||
typedef struct {
|
||||
Service s; ///< IGameMovieTrimmer
|
||||
TransferMemory tmem; ///< TransferMemory
|
||||
} GrcGameMovieTrimmer;
|
||||
|
||||
/// GameMovieId
|
||||
typedef struct {
|
||||
CapsAlbumEntryId album_id; ///< \ref CapsAlbumEntryId
|
||||
u8 reserved[0x28]; ///< Unused, always zero.
|
||||
} GrcGameMovieId;
|
||||
#include "../display/native_window.h"
|
||||
|
||||
/// Stream type values for \ref grcdRead.
|
||||
typedef enum {
|
||||
@ -29,7 +18,58 @@ typedef enum {
|
||||
GrcStream_Audio = 1, ///< Audio stream with PcmFormat_Int16, 2 channels, and samplerate = 48000Hz. Official sw uses buffer size 0x1000.
|
||||
} GrcStream;
|
||||
|
||||
// Trimming
|
||||
/// GameMovieTrimmer
|
||||
typedef struct {
|
||||
Service s; ///< IGameMovieTrimmer
|
||||
TransferMemory tmem; ///< TransferMemory
|
||||
} GrcGameMovieTrimmer;
|
||||
|
||||
/// IMovieMaker
|
||||
typedef struct {
|
||||
Service a; ///< applet IMovieMaker
|
||||
Service s; ///< grc IMovieMaker
|
||||
Service video_proxy; ///< IHOSBinderDriver VideoProxy
|
||||
Event recording_event; ///< Output Event from GetOffscreenLayerRecordingFinishReadyEvent with autoclear=false.
|
||||
Event audio_event; ///< Output Event from GetOffscreenLayerAudioEncodeReadyEvent with autoclear=false.
|
||||
TransferMemory tmem; ///< TransferMemory
|
||||
NWindow win; ///< \ref NWindow
|
||||
u64 layer_handle; ///< LayerHandle
|
||||
bool layer_open; ///< Whether OpenOffscreenLayer was used successfully, indicating that CloseOffscreenLayer should be used during \ref grcMovieMakerClose.
|
||||
bool started_flag; ///< Whether \ref grcMovieMakerStart was used successfully. This is also used by \ref grcMovieMakerAbort.
|
||||
} GrcMovieMaker;
|
||||
|
||||
/// GameMovieId
|
||||
typedef struct {
|
||||
CapsAlbumEntryId album_id; ///< \ref CapsAlbumEntryId
|
||||
u8 reserved[0x28]; ///< Unused, always zero.
|
||||
} GrcGameMovieId;
|
||||
|
||||
/// OffscreenRecordingParameter
|
||||
typedef struct {
|
||||
u8 unk_x0[0x10]; ///< Unknown. Default value is 0.
|
||||
u32 unk_x10; ///< Unknown. Must match value 0x103, which is the default value.
|
||||
|
||||
s32 video_bitrate; ///< VideoBitRate, 0 is invalid. Default value is 8000000.
|
||||
s32 video_width; ///< VideoWidth, must match 1280 or 1920. Default value is 1280.
|
||||
s32 video_height; ///< VideoHeight, must match 720 or 1080. Default value is 720.
|
||||
s32 video_framerate; ///< VideoFrameRate, must match 30 or 60. Default value is 30.
|
||||
s32 video_keyFrameInterval; ///< VideoKeyFrameInterval, 0 is invalid. Default value is 30.
|
||||
|
||||
s32 audio_bitrate; ///< AudioBitRate. Default value is 128000 ([5.0.0-5.1.0] 1536000).
|
||||
s32 audio_samplerate; ///< AudioSampleRate, 0 is invalid. Default value is 48000.
|
||||
s32 audio_channel_count; ///< AudioChannelCount. Must match 2, which is the default value.
|
||||
s32 audio_sample_format; ///< \ref PcmFormat AudioSampleFormat. Must match PcmFormat_Int16, which is the default value.
|
||||
|
||||
s32 video_imageOrientation; ///< \ref AlbumImageOrientation VideoImageOrientation. Default value is ::AlbumImageOrientation_Unknown0.
|
||||
|
||||
u8 unk_x3c[0x44]; ///< Unknown. Default value is 0.
|
||||
} GrcOffscreenRecordingParameter;
|
||||
|
||||
/// Default size for \ref grcCreateMovieMaker, this is the size used by official sw.
|
||||
#define GRC_MOVIEMAKER_WORKMEMORY_SIZE_DEFAULT 0x6000000
|
||||
|
||||
///@name Trimming
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Creates a \ref GrcGameMovieTrimmer using \ref appletCreateGameMovieTrimmer, uses the cmds from it to trim the specified video, then closes it.
|
||||
@ -44,7 +84,90 @@ typedef enum {
|
||||
*/
|
||||
Result grcTrimGameMovie(GrcGameMovieId *dst_movieid, const GrcGameMovieId *src_movieid, size_t tmem_size, const void* thumbnail, s32 start, s32 end);
|
||||
|
||||
// grc:d
|
||||
///@}
|
||||
|
||||
///@name IMovieMaker
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Creates a \ref GrcOffscreenRecordingParameter with the default values, see \ref GrcOffscreenRecordingParameter for the default values.
|
||||
* @param[out] param \ref GrcOffscreenRecordingParameter
|
||||
*/
|
||||
void grcCreateOffscreenRecordingParameter(GrcOffscreenRecordingParameter *param);
|
||||
|
||||
/**
|
||||
* @brief Creates a \ref GrcMovieMaker using \ref appletCreateMovieMaker, and does the required initialization.
|
||||
* @note See \ref appletCreateMovieMaker for the requirements for using this.
|
||||
* @param[out] m \ref GrcMovieMaker
|
||||
* @param[in] size TransferMemory WorkMemory size. See \ref GRC_MOVIEMAKER_WORKMEMORY_SIZE_DEFAULT.
|
||||
*/
|
||||
Result grcCreateMovieMaker(GrcMovieMaker *m, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Closes a \ref GrcMovieMaker.
|
||||
* @note This also uses \ref grcMovieMakerAbort.
|
||||
* @param m \ref GrcMovieMaker
|
||||
*/
|
||||
void grcMovieMakerClose(GrcMovieMaker *m);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref NWindow for the specified MovieMaker.
|
||||
* @param m \ref GrcMovieMaker
|
||||
*/
|
||||
static inline NWindow* grcMovieMakerGetNWindow(GrcMovieMaker *m) {
|
||||
return &m->win;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts recording with the specified MovieMaker and \ref GrcOffscreenRecordingParameter.
|
||||
* @param m \ref GrcMovieMaker
|
||||
* @param[in] param \ref GrcOffscreenRecordingParameter
|
||||
*/
|
||||
Result grcMovieMakerStart(GrcMovieMaker *m, const GrcOffscreenRecordingParameter *param);
|
||||
|
||||
/**
|
||||
* @brief Aborts recording with the specified MovieMaker.
|
||||
* @note This is used automatically by \ref grcMovieMakerClose.
|
||||
* @note This will throw an error if \ref grcMovieMakerStart was not used previously, with the flag used for this being cleared afterwards on success.
|
||||
* @param m \ref GrcMovieMaker
|
||||
*/
|
||||
Result grcMovieMakerAbort(GrcMovieMaker *m);
|
||||
|
||||
/**
|
||||
* @brief Finishes recording with the specified MovieMaker.
|
||||
* @note This automatically uses \ref grcMovieMakerAbort on error.
|
||||
* @note The recorded video will not be accessible via the Album-applet since it's stored separately from other Album data.
|
||||
* @param m \ref GrcMovieMaker
|
||||
* @param width Width for the thumbnail, must be 1280.
|
||||
* @param height Height for the thumbnail, must be 720.
|
||||
* @param[in] userdata UserData input buffer for the JPEG thumbnail. Optional, can be NULL.
|
||||
* @param[in] userdata_size Size of the UserData input buffer. Optional, can be 0. Must be <=0x400.
|
||||
* @param[in] thumbnail RGBA8 image buffer containing the thumbnail. Optional, can be NULL.
|
||||
* @param[in] thumbnail_size Size of the thumbnail buffer. Optional, can be 0.
|
||||
* @param[out] entry Output \ref CapsApplicationAlbumEntry for the recorded video. Optional, can be NULL. Only available on [7.0.0+], if this is not NULL on pre-7.0.0 an error is thrown.
|
||||
*/
|
||||
Result grcMovieMakerFinish(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry);
|
||||
|
||||
/**
|
||||
* @brief Gets the recording error with the specified MovieMaker.
|
||||
* @param m \ref GrcMovieMaker
|
||||
*/
|
||||
Result grcMovieMakerGetError(GrcMovieMaker *m);
|
||||
|
||||
/**
|
||||
* @brief Encodes audio sample data with the specified MovieMaker.
|
||||
* @note This waits on the event and uses the cmd repeatedly until the entire input buffer is handled.
|
||||
* @note If you don't use this the recorded video will be missing audio.
|
||||
* @param m \ref GrcMovieMaker
|
||||
* @param[in] buffer Audio buffer.
|
||||
* @param[in] size Size of the buffer.
|
||||
*/
|
||||
Result grcMovieMakerEncodeAudioSample(GrcMovieMaker *m, const void* buffer, size_t size);
|
||||
|
||||
///@}
|
||||
|
||||
///@name grc:d
|
||||
///@{
|
||||
|
||||
/// Initialize grc:d.
|
||||
Result grcdInitialize(void);
|
||||
@ -70,3 +193,5 @@ Result grcdBegin(void);
|
||||
*/
|
||||
Result grcdRead(GrcStream stream, void* buffer, size_t size, u32 *unk, u32 *data_size, u64 *timestamp);
|
||||
|
||||
///@}
|
||||
|
||||
|
||||
@ -222,6 +222,9 @@ typedef enum
|
||||
TYPE_JOYCON_PAIR = BIT(2),
|
||||
TYPE_JOYCON_LEFT = BIT(3),
|
||||
TYPE_JOYCON_RIGHT = BIT(4),
|
||||
|
||||
TYPE_SYSTEM_EXT = BIT(29),
|
||||
TYPE_SYSTEM = BIT(30),
|
||||
} HidControllerType;
|
||||
|
||||
typedef enum
|
||||
@ -240,6 +243,7 @@ typedef enum
|
||||
COLORS_NONEXISTENT = BIT(1),
|
||||
} HidControllerColorDescription;
|
||||
|
||||
/// HidControllerKeys
|
||||
typedef enum
|
||||
{
|
||||
KEY_A = BIT(0), ///< A
|
||||
@ -327,6 +331,52 @@ typedef enum
|
||||
HidJoyHoldType_Horizontal = 1, ///< Joy-Con held horizontally with HID state orientation adjustment, see \ref HidControllerLayoutType.
|
||||
} HidJoyHoldType;
|
||||
|
||||
/// DeviceType
|
||||
typedef enum {
|
||||
HidDeviceTypeBits_FullKey = BIT(0), ///< Pro Controller and Gc controller.
|
||||
HidDeviceTypeBits_Unknown1 = BIT(1), ///< Unknown.
|
||||
HidDeviceTypeBits_HandheldLeft = BIT(2), ///< Joy-Con/Famicom/NES left controller in handheld mode.
|
||||
HidDeviceTypeBits_HandheldRight = BIT(3), ///< Joy-Con/Famicom/NES right controller in handheld mode.
|
||||
HidDeviceTypeBits_JoyLeft = BIT(4), ///< Joy-Con left controller.
|
||||
HidDeviceTypeBits_JoyRight = BIT(5), ///< Joy-Con right controller.
|
||||
HidDeviceTypeBits_Palma = BIT(6), ///< Poké Ball Plus controller.
|
||||
HidDeviceTypeBits_LarkLeftHVC = BIT(7), ///< Famicom left controller.
|
||||
HidDeviceTypeBits_LarkRightHVC = BIT(8), ///< Famicom right controller (with microphone).
|
||||
HidDeviceTypeBits_LarkLeftNES = BIT(9), ///< NES left controller.
|
||||
HidDeviceTypeBits_LarkRightNES = BIT(10), ///< NES right controller.
|
||||
HidDeviceTypeBits_SystemExt = BIT(15), ///< Generic external controller.
|
||||
HidDeviceTypeBits_System = BIT(31), ///< Generic controller.
|
||||
} HidDeviceTypeBits;
|
||||
|
||||
/// Internal DeviceType for [9.0.0+]. Converted to/from the pre-9.0.0 version of this by the hiddbg funcs.
|
||||
typedef enum {
|
||||
HidDeviceType_JoyRight1 = 1, ///< ::HidDeviceTypeBits_JoyRight
|
||||
HidDeviceType_JoyLeft2 = 2, ///< ::HidDeviceTypeBits_JoyLeft
|
||||
HidDeviceType_FullKey3 = 3, ///< ::HidDeviceTypeBits_FullKey
|
||||
HidDeviceType_JoyLeft4 = 4, ///< ::HidDeviceTypeBits_JoyLeft
|
||||
HidDeviceType_JoyRight5 = 5, ///< ::HidDeviceTypeBits_JoyRight
|
||||
HidDeviceType_FullKey6 = 6, ///< ::HidDeviceTypeBits_FullKey
|
||||
HidDeviceType_LarkLeftHVC = 7, ///< ::HidDeviceTypeBits_LarkLeftHVC
|
||||
HidDeviceType_LarkRightHVC = 8, ///< ::HidDeviceTypeBits_LarkRightHVC
|
||||
HidDeviceType_LarkLeftNES = 9, ///< ::HidDeviceTypeBits_LarkLeftNES
|
||||
HidDeviceType_LarkRightNES = 10, ///< ::HidDeviceTypeBits_LarkRightNES
|
||||
HidDeviceType_Palma = 12, ///< [9.0.0+] ::HidDeviceTypeBits_Palma
|
||||
HidDeviceType_FullKey13 = 13, ///< ::HidDeviceTypeBits_FullKey
|
||||
HidDeviceType_FullKey15 = 15, ///< ::HidDeviceTypeBits_FullKey
|
||||
HidDeviceType_System19 = 19, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_PROCONTROLLER.
|
||||
HidDeviceType_System20 = 20, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
|
||||
HidDeviceType_System21 = 21, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
|
||||
} HidDeviceType;
|
||||
|
||||
/// NpadInterfaceType
|
||||
typedef enum
|
||||
{
|
||||
NpadInterfaceType_Bluetooth = 1, ///< Bluetooth.
|
||||
NpadInterfaceType_Rail = 2, ///< Rail.
|
||||
NpadInterfaceType_USB = 3, ///< USB.
|
||||
NpadInterfaceType_Unknown4 = 4, ///< Unknown.
|
||||
} HidNpadInterfaceType;
|
||||
|
||||
typedef struct touchPosition
|
||||
{
|
||||
u32 id;
|
||||
@ -666,7 +716,7 @@ HidControllerType hidGetControllerType(HidControllerID id);
|
||||
void hidGetControllerColors(HidControllerID id, HidControllerColors *colors);
|
||||
bool hidIsControllerConnected(HidControllerID id);
|
||||
|
||||
/// Gets the DeviceType for the specified controller.
|
||||
/// Gets the \ref HidDeviceTypeBits for the specified controller.
|
||||
u32 hidGetControllerDeviceType(HidControllerID id);
|
||||
|
||||
/// Gets the flags for the specified controller.
|
||||
@ -789,3 +839,7 @@ Result hidGetSevenSixAxisSensorFusionStrength(float *strength);
|
||||
/// Resets the timestamp for the SevenSixAxisSensor. Only available on [6.0.0+].
|
||||
Result hidResetSevenSixAxisSensorTimestamp(void);
|
||||
|
||||
/// Gets the \ref HidNpadInterfaceType for the specified controller.
|
||||
/// Only available on [4.0.0+].
|
||||
Result hidGetNpadInterfaceType(HidControllerID id, u8 *out);
|
||||
|
||||
|
||||
@ -8,16 +8,27 @@
|
||||
#include "../services/hid.h"
|
||||
#include "../services/sm.h"
|
||||
|
||||
/// HdlsDeviceInfo
|
||||
/// HdlsDeviceInfo, for [7.0.0-8.1.0].
|
||||
typedef struct {
|
||||
u32 type; ///< Only one bit can be set. BIT(N*4+0) = Pro-Controller, BIT(N*4+1) = Joy-Con Left, BIT(N*4+2) = Joy-Con Right, BIT(N*4+3) = invalid. Where N is 0-1. BIT(8-10) = Pro-Controller, BIT(11) = Famicom-Controller, BIT(12) = Famicom-Controller II with microphone, BIT(13) = NES-Controller(DeviceType=0x200), BIT(14) = NES-Controller(DeviceType=0x400), BIT(15-16) = invalid, BIT(17) = unknown(DeviceType=0x8000), BIT(18-20) = invalid, BIT(21-23) = unknown(DeviceType=0x80000000).
|
||||
u32 singleColorBody; ///< RGBA Single Body Color
|
||||
u32 singleColorButtons; ///< RGBA Single Buttons Color
|
||||
u8 type2; ///< Additional type field used with the above type field (only applies to type bit0-bit2 and bit21), if the value doesn't match one of the following a default is used. Type Pro-Controller: value 0x3 indicates that the controller is connected via USB. Type BIT(21): value 0x3 = unknown. When value is 0x2, state is merged with an existing controller (when the type value is compatible with this). Otherwise, it's a dedicated controller.
|
||||
u8 pad[0x3]; ///< Padding
|
||||
u32 deviceTypeInternal; ///< Only one bit can be set. BIT(N*4+0) = Pro-Controller, BIT(N*4+1) = Joy-Con Left, BIT(N*4+2) = Joy-Con Right, BIT(N*4+3) = invalid. Where N is 0-1. BIT(8-10) = Pro-Controller, BIT(11) = Famicom-Controller, BIT(12) = Famicom-Controller II with microphone, BIT(13) = NES-Controller(DeviceType=0x200), BIT(14) = NES-Controller(DeviceType=0x400), BIT(15-16) = invalid, BIT(17) = unknown(DeviceType=0x8000), BIT(18-20) = invalid, BIT(21-23) = unknown(DeviceType=0x80000000).
|
||||
u32 singleColorBody; ///< RGBA Single Body Color.
|
||||
u32 singleColorButtons; ///< RGBA Single Buttons Color.
|
||||
u8 npadInterfaceType; ///< \ref HidNpadInterfaceType. Additional type field used with the above type field (only applies to type bit0-bit2 and bit21), if the value doesn't match one of the following a default is used. Type Pro-Controller: value 0x3 indicates that the controller is connected via USB. Type BIT(21): value 0x3 = unknown. When value is 0x2, state is merged with an existing controller (when the type value is compatible with this). Otherwise, it's a dedicated controller.
|
||||
u8 pad[0x3]; ///< Padding.
|
||||
} HiddbgHdlsDeviceInfoV7;
|
||||
|
||||
/// HdlsDeviceInfo, for [9.0.0+]. Converted to/from \ref HiddbgHdlsDeviceInfoV7 on prior sysvers.
|
||||
typedef struct {
|
||||
u8 deviceType; ///< \ref HidDeviceType
|
||||
u8 npadInterfaceType; ///< \ref HidNpadInterfaceType. Additional type field used with the above type field (only applies to ::HidDeviceType_JoyRight1, ::HidDeviceType_JoyLeft2, ::HidDeviceType_FullKey3, and ::HidDeviceType_System19), if the value doesn't match one of the following a default is used. ::HidDeviceType_FullKey3: ::NpadInterfaceType_USB indicates that the controller is connected via USB. :::HidDeviceType_System19: ::NpadInterfaceType_USB = unknown. When value is ::NpadInterfaceType_Rail, state is merged with an existing controller (with ::HidDeviceType_JoyRight1 / ::HidDeviceType_JoyLeft2). Otherwise, it's a dedicated controller.
|
||||
u8 pad[0x2]; ///< Padding.
|
||||
u32 singleColorBody; ///< RGBA Single Body Color.
|
||||
u32 singleColorButtons; ///< RGBA Single Buttons Color.
|
||||
u32 colorLeftGrip; ///< [9.0.0+] RGBA Left Grip Color.
|
||||
u32 colorRightGrip; ///< [9.0.0+] RGBA Right Grip Color.
|
||||
} HiddbgHdlsDeviceInfo;
|
||||
|
||||
/// HdlsState
|
||||
/// HdlsState, for [7.0.0-8.1.0].
|
||||
typedef struct {
|
||||
u8 powerConnected; ///< powerConnected for the main PowerInfo, see \ref HidFlags.
|
||||
u8 flags; ///< ORRed with powerConnected to set the value of the first byte for \ref HidFlags. For example, value 1 here will set isCharging for the main PowerInfo.
|
||||
@ -27,6 +38,16 @@ typedef struct {
|
||||
JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition
|
||||
u8 unk_x20; ///< Unused for input. Set with output from \ref hiddbgDumpHdlsStates. Not set by \ref hiddbgGetAbstractedPadsState.
|
||||
u8 padding[0x3]; ///< Padding
|
||||
} HiddbgHdlsStateV7;
|
||||
|
||||
/// HdlsState, for [9.0.0+]. Converted to/from \ref HiddbgHdlsDeviceInfoV7 on prior sysvers.
|
||||
typedef struct {
|
||||
u32 batteryCharge; ///< batteryCharge for the main PowerInfo, see \ref HidPowerInfo.
|
||||
u32 flags; ///< Used to set the main PowerInfo for \ref HidFlags. BIT(0) -> powerConnected, BIT(1) -> isCharging.
|
||||
u64 buttons; ///< See \ref HidControllerKeys. [9.0.0+] Masked with 0xfffffffff00fffff.
|
||||
JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition
|
||||
u8 unk_x20; ///< Unused for input. Set with output from \ref hiddbgDumpHdlsStates.
|
||||
u8 padding[0x3]; ///< Padding
|
||||
} HiddbgHdlsState;
|
||||
|
||||
/// HdlsNpadAssignmentEntry
|
||||
@ -46,14 +67,29 @@ typedef struct {
|
||||
HiddbgHdlsNpadAssignmentEntry entries[0x10]; ///< \ref HiddbgHdlsNpadAssignmentEntry
|
||||
} HiddbgHdlsNpadAssignment;
|
||||
|
||||
/// HdlsStateListEntry
|
||||
/// HdlsStateListEntryV7, for [7.0.0-8.1.0].
|
||||
typedef struct {
|
||||
u64 HdlsHandle; ///< HdlsHandle
|
||||
HiddbgHdlsDeviceInfoV7 device; ///< \ref HiddbgHdlsDeviceInfoV7. With \ref hiddbgApplyHdlsStateList this is only used when creating new devices.
|
||||
HiddbgHdlsStateV7 state; ///< \ref HiddbgHdlsState
|
||||
} HiddbgHdlsStateListEntryV7;
|
||||
|
||||
/// HdlsStateListV7, for [7.0.0-8.1.0]. This contains a list of all controllers, including non-virtual controllers.
|
||||
typedef struct {
|
||||
s32 total_entries; ///< Total entries for the below entries.
|
||||
u32 pad; ///< Padding
|
||||
HiddbgHdlsStateListEntryV7 entries[0x10]; ///< \ref HiddbgHdlsStateListEntryV7
|
||||
} HiddbgHdlsStateListV7;
|
||||
|
||||
/// HdlsStateListEntry, for [9.0.0+]. Converted to/from \ref HiddbgHdlsStateListEntryV7 on prior sysvers.
|
||||
typedef struct {
|
||||
u64 HdlsHandle; ///< HdlsHandle
|
||||
HiddbgHdlsDeviceInfo device; ///< \ref HiddbgHdlsDeviceInfo. With \ref hiddbgApplyHdlsStateList this is only used when creating new devices.
|
||||
HiddbgHdlsState state; ///< \ref HiddbgHdlsState
|
||||
alignas(8) HiddbgHdlsState state; ///< \ref HiddbgHdlsState
|
||||
} HiddbgHdlsStateListEntry;
|
||||
|
||||
/// HdlsStateList. This contains a list of all controllers, including non-virtual controllers.
|
||||
/// HdlsStateList, for [9.0.0+]. Converted to/from \ref HiddbgHdlsStateListV7 on prior sysvers.
|
||||
/// This contains a list of all controllers, including non-virtual controllers.
|
||||
typedef struct {
|
||||
s32 total_entries; ///< Total entries for the below entries.
|
||||
u32 pad; ///< Padding
|
||||
@ -62,16 +98,16 @@ typedef struct {
|
||||
|
||||
/// AbstractedPadState
|
||||
typedef struct {
|
||||
u32 type; ///< Type. Converted to HiddbgHdlsDeviceInfo::type internally by \ref hiddbgSetAutoPilotVirtualPadState. BIT(0) -> BIT(0), BIT(1) -> BIT(15), BIT(2-3) -> BIT(1-2), BIT(4-5) -> BIT(1-2), BIT(6) -> BIT(3). BIT(7-11) -> BIT(11-15), BIT(12-14) -> BIT(12-14), BIT(15) -> BIT(17), BIT(31) -> BIT(21).
|
||||
u32 type; ///< Type. Converted to HiddbgHdlsDeviceInfoV7::type internally by \ref hiddbgSetAutoPilotVirtualPadState. BIT(0) -> BIT(0), BIT(1) -> BIT(15), BIT(2-3) -> BIT(1-2), BIT(4-5) -> BIT(1-2), BIT(6) -> BIT(3). BIT(7-11) -> BIT(11-15), BIT(12-14) -> BIT(12-14), BIT(15) -> BIT(17), BIT(31) -> BIT(21).
|
||||
u8 flags; ///< Flags. Only bit0 is used by \ref hiddbgSetAutoPilotVirtualPadState: when clear it will skip using the rest of the input and run \ref hiddbgUnsetAutoPilotVirtualPadState internally.
|
||||
u8 pad[0x3]; ///< Padding
|
||||
|
||||
u32 singleColorBody; ///< RGBA Single Body Color
|
||||
u32 singleColorButtons; ///< RGBA Single Buttons Color
|
||||
u8 type2; ///< See HiddbgHdlsDeviceInfo::type2.
|
||||
u8 npadInterfaceType; ///< See HiddbgHdlsDeviceInfo::npadInterfaceType.
|
||||
u8 pad2[0x3]; ///< Padding
|
||||
|
||||
HiddbgHdlsState state; ///< State
|
||||
HiddbgHdlsStateV7 state; ///< State
|
||||
|
||||
u8 unused[0x60]; ///< Unused with \ref hiddbgSetAutoPilotVirtualPadState. Not set by \ref hiddbgGetAbstractedPadsState.
|
||||
} HiddbgAbstractedPadState;
|
||||
@ -90,20 +126,30 @@ Result hiddbgUpdateDesignInfo(u32 colorBody, u32 colorButtons, u32 colorLeftGrip
|
||||
/// This doesn't seem to be usable?
|
||||
Result hiddbgReadSerialFlash(u32 offset, void* buffer, size_t size, u64 UniquePadId);
|
||||
|
||||
/// Gets a list of AbstractedPadHandles, where AbstractedPadHandles is the output array with max entries = count. total_entries is total entries written to the output array. Only available with [5.0.0+].
|
||||
/// Gets the internal DeviceType for the specified controller. See hidsys.h for UniquePadId.
|
||||
/// Only available with [6.0.0+].
|
||||
/// Pre-9.0.0 the output is an u32, with [9.0.0+] it's an u8.
|
||||
Result hiddbgGetUniquePadDeviceTypeSetInternal(u64 UniquePadId, u32 *out);
|
||||
|
||||
/// Gets a list of AbstractedPadHandles, where AbstractedPadHandles is the output array with max entries = count. total_entries is total entries written to the output array.
|
||||
/// Only available with [5.0.0-8.1.0].
|
||||
Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries);
|
||||
|
||||
/// Gets the state for the specified AbstractedPadHandle. Only available with [5.0.0+].
|
||||
/// Gets the state for the specified AbstractedPadHandle.
|
||||
/// Only available with [5.0.0-8.1.0].
|
||||
Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state);
|
||||
|
||||
/// Similar to \ref hiddbgGetAbstractedPadHandles except this also returns the state for each pad in output array states. Only available with [5.0.0+].
|
||||
/// Similar to \ref hiddbgGetAbstractedPadHandles except this also returns the state for each pad in output array states.
|
||||
/// Only available with [5.0.0-8.1.0].
|
||||
Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries);
|
||||
|
||||
/// Sets AutoPilot state for the specified pad.
|
||||
/// AbstractedVirtualPadId can be any unique value as long as it's within bounds. For example, 0-7 is usable.
|
||||
/// Only available with [5.0.0-8.1.0].
|
||||
Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state);
|
||||
|
||||
/// Clears AutoPilot state for the specified pad set by \ref hiddbgSetAutoPilotVirtualPadState.
|
||||
/// Only available with [5.0.0-8.1.0].
|
||||
Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId);
|
||||
|
||||
/// Clears AutoPilot state for all pads set by \ref hiddbgSetAutoPilotVirtualPadState.
|
||||
|
||||
@ -43,6 +43,11 @@ Result hidsysEnableAppletToGetInput(bool enable);
|
||||
**/
|
||||
Result hidsysAcquireHomeButtonEventHandle(Event* event_out);
|
||||
|
||||
/**
|
||||
* @brief Returns an event that fires when the capture button is pressed. This event does not auto clear.
|
||||
**/
|
||||
Result hidsysAcquireCaptureButtonEventHandle(Event* event_out);
|
||||
|
||||
Result hidsysActivateHomeButton(void);
|
||||
Result hidsysActivateSleepButton(void);
|
||||
Result hidsysActivateCaptureButton(void);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/fs.h"
|
||||
|
||||
typedef struct {
|
||||
@ -31,10 +31,10 @@ Result lrLrRedirectProgramPath(LrLocationResolver* lr, u64 tid, const char *path
|
||||
Result lrLrResolveApplicationControlPath(LrLocationResolver* lr, u64 tid, char *out);
|
||||
Result lrLrResolveApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, char *out);
|
||||
Result lrLrResolveDataPath(LrLocationResolver* lr, u64 tid, char *out);
|
||||
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, const char *path);
|
||||
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, const char *path);
|
||||
Result lrLrResolveLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out);
|
||||
Result lrLrRedirectLegalInformationPath(LrLocationResolver* lr, u64 tid, const char *path);
|
||||
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
|
||||
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
|
||||
Result lrLrResolveApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out);
|
||||
Result lrLrRedirectApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
|
||||
Result lrLrRefresh(LrLocationResolver* lr);
|
||||
|
||||
// IRegisteredLocationResolver
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file ncm.h
|
||||
* @brief Content Manager (ncm) service IPC wrapper.
|
||||
* @author zhuowei & Adubbz
|
||||
* @author Adubbz & zhuowei
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
@ -9,102 +9,190 @@
|
||||
#include "../services/fs.h"
|
||||
#include "../services/sm.h"
|
||||
|
||||
typedef enum {
|
||||
NcmContentType_CNMT = 0,
|
||||
NcmContentType_Program = 1,
|
||||
NcmContentType_Data = 2,
|
||||
NcmContentType_Icon = 3,
|
||||
NcmContentType_Doc = 4,
|
||||
NcmContentType_Info = 5,
|
||||
} NcmContentType;
|
||||
|
||||
typedef enum {
|
||||
NcmContentMetaType_SystemProgram = 0x01,
|
||||
NcmContentMetaType_SystemData = 0x02,
|
||||
NcmContentMetaType_SystemUpdate = 0x03,
|
||||
NcmContentMetaType_BootImagePackage = 0x04,
|
||||
NcmContentMetaType_BootImagePackageSafe = 0x05,
|
||||
NcmContentMetaType_Application = 0x80,
|
||||
NcmContentMetaType_Patch = 0x81,
|
||||
NcmContentMetaType_AddOnContent = 0x82,
|
||||
NcmContentMetaType_Delta = 0x83,
|
||||
} NcmContentMetaType;
|
||||
|
||||
typedef enum {
|
||||
NcmContentMetaAttribute_Exfat = (1 << 0),
|
||||
NcmContentMetaAttribute_Rebootless = (1 << 1),
|
||||
} NcmContentMetaAttribute;
|
||||
|
||||
/// ContentStorage
|
||||
typedef struct {
|
||||
Service s;
|
||||
Service s; ///< IContentStorage
|
||||
} NcmContentStorage;
|
||||
|
||||
/// ContentMetaDatabase
|
||||
typedef struct {
|
||||
Service s;
|
||||
Service s; ///< IContentMetaDatabase
|
||||
} NcmContentMetaDatabase;
|
||||
|
||||
/// ContentType
|
||||
typedef enum {
|
||||
NcmContentType_Meta = 0, ///< Meta
|
||||
NcmContentType_Program = 1, ///< Program
|
||||
NcmContentType_Data = 2, ///< Data
|
||||
NcmContentType_Control = 3, ///< Control
|
||||
NcmContentType_HtmlDocument = 4, ///< HtmlDocument
|
||||
NcmContentType_LegalInformation = 5, ///< LegalInformation
|
||||
NcmContentType_DeltaFragment = 6, ///< DeltaFragment
|
||||
} NcmContentType;
|
||||
|
||||
/// ContentMetaType
|
||||
typedef enum {
|
||||
NcmContentMetaType_Unknown = 0x0, ///< Unknown
|
||||
NcmContentMetaType_SystemProgram = 0x1, ///< SystemProgram
|
||||
NcmContentMetaType_SystemData = 0x2, ///< SystemData
|
||||
NcmContentMetaType_SystemUpdate = 0x3, ///< SystemUpdate
|
||||
NcmContentMetaType_BootImagePackage = 0x4, ///< BootImagePackage
|
||||
NcmContentMetaType_BootImagePackageSafe = 0x5, ///< BootImagePackageSafe
|
||||
NcmContentMetaType_Application = 0x80, ///< Application
|
||||
NcmContentMetaType_Patch = 0x81, ///< Patch
|
||||
NcmContentMetaType_AddOnContent = 0x82, ///< AddOnContent
|
||||
NcmContentMetaType_Delta = 0x83, ///< Delta
|
||||
} NcmContentMetaType;
|
||||
|
||||
/// ContentMetaAttribute
|
||||
typedef enum {
|
||||
NcmContentMetaAttribute_None = 0, ///< None
|
||||
NcmContentMetaAttribute_IncludesExFatDriver = BIT(0), ///< IncludesExFatDriver
|
||||
NcmContentMetaAttribute_Rebootless = BIT(1), ///< Rebootless
|
||||
} NcmContentMetaAttribute;
|
||||
|
||||
/// ContentInstallType
|
||||
typedef enum {
|
||||
NcmContentInstallType_Full = 0, ///< Full
|
||||
NcmContentInstallType_FragmentOnly = 1, ///< FragmentOnly
|
||||
NcmContentInstallType_Unknown = 7, ///< Unknown
|
||||
} NcmContentInstallType;
|
||||
|
||||
/// NcaId
|
||||
typedef struct {
|
||||
u8 c[0x10];
|
||||
u8 c[0x10]; ///< Id
|
||||
} NcmNcaId;
|
||||
|
||||
/// ContentMetaKey
|
||||
typedef struct {
|
||||
u64 titleId;
|
||||
u32 version;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
u8 padding[2];
|
||||
} NcmMetaRecord;
|
||||
u64 title_id; ///< Title id.
|
||||
u32 version; ///< Title version.
|
||||
u8 type; ///< \ref NcmContentMetaType
|
||||
u8 install_type; ///< \ref NcmContentInstallType
|
||||
u8 padding[2]; ///< Padding.
|
||||
} NcmContentMetaKey;
|
||||
|
||||
/// ApplicationContentMetaKey
|
||||
typedef struct {
|
||||
NcmNcaId ncaId;
|
||||
u8 size[0x6];
|
||||
u8 type;
|
||||
u8 padding;
|
||||
} NcmContentRecord;
|
||||
|
||||
typedef struct {
|
||||
u16 numExtraBytes; ///< Size of optional struct that comes after this one.
|
||||
u16 numContentRecords; ///< Number of NcmContentRecord entries after the extra bytes.
|
||||
u16 numMetaRecords; ///< Number of NcmMetaRecord entries that come after the NcmContentRecords.
|
||||
u16 padding; ///< Always zero.
|
||||
} NcmContentMetaRecordsHeader;
|
||||
|
||||
typedef struct {
|
||||
NcmMetaRecord metaRecord;
|
||||
u64 baseTitleId;
|
||||
NcmContentMetaKey key; ///< \ref NcmContentMetaKey
|
||||
u64 application_id; ///< Title id of an application.
|
||||
} NcmApplicationContentMetaKey;
|
||||
|
||||
/// ContentInfo
|
||||
typedef struct {
|
||||
NcmNcaId content_id; ///< \ref NcmNcaId
|
||||
u8 size[0x6]; ///< Content size.
|
||||
u8 content_type; ///< \ref NcmContentType.
|
||||
u8 id_offset; ///< Offset of this content. Unused by most applications.
|
||||
} NcmContentInfo;
|
||||
|
||||
/// Used by system updates. They share the exact same struct as NcmContentMetaKey
|
||||
typedef NcmContentMetaKey NcmContentMetaInfo;
|
||||
|
||||
/// ContentMetaHeader
|
||||
typedef struct {
|
||||
u16 extended_header_size; ///< Size of optional struct that comes after this one.
|
||||
u16 content_count; ///< Number of NcmContentInfos after the extra bytes.
|
||||
u16 content_meta_count; ///< Number of NcmContentMetaInfos that come after the NcmContentInfos.
|
||||
u8 attributes; ///< Usually None (0).
|
||||
u8 storage_id; ///< Usually None (0).
|
||||
} NcmContentMetaHeader;
|
||||
|
||||
/// ApplicationMetaExtendedHeader
|
||||
typedef struct {
|
||||
u64 patch_id; ///< Title id of this application's patch.
|
||||
u32 required_system_version; ///< Firmware version required by this application.
|
||||
u32 required_application_version; ///< [9.0.0+] Owner application version required by this application. Previously padding.
|
||||
} NcmApplicationMetaExtendedHeader;
|
||||
|
||||
/// PatchMetaExtendedHeader
|
||||
typedef struct {
|
||||
u64 application_id; ///< Title id of this patch's corresponding application.
|
||||
u32 required_system_version; ///< Firmware version required by this patch.
|
||||
u32 extended_data_size; ///< Size of the extended data following the NcmContentInfos.
|
||||
u8 reserved[0x8]; ///< Unused.
|
||||
} NcmPatchMetaExtendedHeader;
|
||||
|
||||
/// AddOnContentMetaExtendedHeader
|
||||
typedef struct {
|
||||
u64 application_id; ///< Title id of this add-on-content's corresponding application.
|
||||
u32 required_application_version; ///< Version of the application required by this add-on-content.
|
||||
u32 padding; ///< Padding.
|
||||
} NcmAddOnContentMetaExtendedHeader;
|
||||
|
||||
/// SystemUpdateMetaExtendedHeader
|
||||
typedef struct {
|
||||
u32 extended_data_size; ///< Size of the extended data after NcmContentInfos and NcmContentMetaInfos.
|
||||
} NcmSystemUpdateMetaExtendedHeader;
|
||||
|
||||
Result ncmInitialize(void);
|
||||
void ncmExit(void);
|
||||
Service* ncmGetServiceSession(void);
|
||||
|
||||
Result ncmOpenContentStorage(FsStorageId storage, NcmContentStorage* out);
|
||||
Result ncmOpenContentMetaDatabase(FsStorageId storage, NcmContentMetaDatabase* out);
|
||||
Result ncmCreateContentStorage(FsStorageId storage_id);
|
||||
Result ncmCreateContentMetaDatabase(FsStorageId storage_id);
|
||||
Result ncmVerifyContentStorage(FsStorageId storage_id);
|
||||
Result ncmVerifyContentMetaDatabase(FsStorageId storage_id);
|
||||
Result ncmOpenContentStorage(NcmContentStorage* out_content_storage, FsStorageId storage_id);
|
||||
Result ncmOpenContentMetaDatabase(NcmContentMetaDatabase* out_content_meta_database, FsStorageId storage_id);
|
||||
Result ncmCloseContentStorageForcibly(FsStorageId storage_id); ///< [1.0.0]
|
||||
Result ncmCloseContentMetaDatabaseForcibly(FsStorageId storage_id); ///< [1.0.0]
|
||||
Result ncmCleanupContentMetaDatabase(FsStorageId storage_id);
|
||||
Result ncmActivateContentStorage(FsStorageId storage_id); ///< [2.0.0+]
|
||||
Result ncmInactivateContentStorage(FsStorageId storage_id); ///< [2.0.0+]
|
||||
Result ncmActivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+]
|
||||
Result ncmInactivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+]
|
||||
Result ncmInvalidateRightsIdCache(void); ///< [9.0.0+]
|
||||
|
||||
Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* outputId);
|
||||
Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId, u64 size);
|
||||
Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId);
|
||||
Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId, u64 offset, const void* srcData, size_t srcDataSize);
|
||||
Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId);
|
||||
Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* registeredId);
|
||||
Result ncmContentStorageHas(NcmContentStorage* cs, const NcmNcaId* ncaId, bool* out);
|
||||
Result ncmContentStorageGetPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize);
|
||||
Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize);
|
||||
void ncmContentStorageClose(NcmContentStorage* cs);
|
||||
Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* out_id);
|
||||
Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id, u64 size);
|
||||
Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id);
|
||||
Result ncmContentStorageHasPlaceHolder(NcmContentStorage* cs, bool* out, const NcmNcaId* placeholder_id);
|
||||
Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 offset, const void* data, size_t data_size);
|
||||
Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id);
|
||||
Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* content_id);
|
||||
Result ncmContentStorageHas(NcmContentStorage* cs, bool* out, const NcmNcaId* content_id);
|
||||
Result ncmContentStorageGetPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmNcaId* content_id);
|
||||
Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const char* out_path, size_t out_size, const NcmNcaId* placeholder_id);
|
||||
Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs);
|
||||
Result ncmContentStorageGetSize(NcmContentStorage* cs, const NcmNcaId* ncaId, u64* out);
|
||||
Result ncmContentStorageListPlaceHolder(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count);
|
||||
Result ncmContentStorageGetContentCount(NcmContentStorage* cs, u32* out_count);
|
||||
Result ncmContentStorageListContentId(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count, u32 start_offset);
|
||||
Result ncmContentStorageGetSizeFromContentId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* content_id);
|
||||
Result ncmContentStorageDisableForcibly(NcmContentStorage* cs);
|
||||
Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, const NcmNcaId* ncaId, u64 offset, void* outBuf, size_t bufSize);
|
||||
Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, const NcmNcaId* ncaId, FsRightsId* rightsIdOut, u32* keyGenerationOut);
|
||||
Result ncmContentStorageRevertToPlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, const NcmNcaId* old_content_id, const NcmNcaId* new_content_id); ///< [2.0.0+]
|
||||
Result ncmContentStorageSetPlaceHolderSize(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 size); ///< [2.0.0+]
|
||||
Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, void* out_data, size_t out_data_size, const NcmNcaId* content_id, u64 offset); ///< [2.0.0+]
|
||||
Result ncmContentStorageGetRightsIdFromPlaceHolderId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id); ///< [2.0.0+]
|
||||
Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* content_id); ///< [2.0.0+]
|
||||
Result ncmContentStorageWriteContentForDebug(NcmContentStorage* cs, const NcmNcaId* content_id, u64 offset, const void* data, size_t data_size); ///< [2.0.0+]
|
||||
Result ncmContentStorageGetFreeSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+]
|
||||
Result ncmContentStorageGetTotalSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+]
|
||||
Result ncmContentStorageFlushPlaceHolder(NcmContentStorage* cs); ///< [3.0.0+]
|
||||
Result ncmContentStorageGetSizeFromPlaceHolderId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* placeholder_id); ///< [4.0.0+]
|
||||
Result ncmContentStorageRepairInvalidFileAttribute(NcmContentStorage* cs); ///< [4.0.0+]
|
||||
Result ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id, const NcmNcaId* cache_content_id); ///< [8.0.0+]
|
||||
|
||||
Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 inDataSize, const NcmContentMetaRecordsHeader* srcRecordsData);
|
||||
Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 outDataSize, NcmContentMetaRecordsHeader* outRecordsData, u64* sizeRead);
|
||||
Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmMetaRecord *record);
|
||||
Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmContentType contentType, const NcmMetaRecord* record, NcmNcaId* out);
|
||||
Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u32 index, NcmContentRecord* contentRecordsOut, size_t contentRecordsBufSize, u32* numEntriesRead);
|
||||
Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32 titleType, u64 titleIdExact, u64 titleIdLow, u64 titleIdHigh, NcmMetaRecord* metaRecordsOut, size_t metaRecordsBufSize, u32* numEntriesWritten, u32* numEntriesTotal);
|
||||
Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, u64 titleId, NcmMetaRecord* out);
|
||||
Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u8 filter, NcmApplicationContentMetaKey* outBuf, size_t outBufSize, u32* numEntriesWritten, u32* numEntriesTotal);
|
||||
Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, const NcmMetaRecord* record, bool* out);
|
||||
void ncmContentMetaDatabaseClose(NcmContentMetaDatabase* db);
|
||||
Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, const void* data, u64 data_size);
|
||||
Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u64* out_size, void* out_data, u64 out_data_size);
|
||||
Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmContentMetaKey *key);
|
||||
Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type);
|
||||
Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, u32* out_entries_written, NcmContentInfo* out_info, size_t out_info_size, const NcmContentMetaKey* key, u32 start_index);
|
||||
Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type, u64 application_title_id, u64 title_id_min, u64 title_id_max, NcmContentInstallType install_type);
|
||||
Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, NcmContentMetaKey* out_key, u64 title_id);
|
||||
Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmApplicationContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type);
|
||||
Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key);
|
||||
Result ncmContentMetaDatabaseHasAll(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* keys, size_t keys_size);
|
||||
Result ncmContentMetaDatabaseGetSize(NcmContentMetaDatabase* db, u64* out_size, const NcmContentMetaKey* key);
|
||||
Result ncmContentMetaDatabaseGetRequiredSystemVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key);
|
||||
Result ncmContentMetaDatabaseGetPatchId(NcmContentMetaDatabase* db, u64* out_patch_id, const NcmContentMetaKey* key);
|
||||
Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db);
|
||||
Result ncmContentMetaDatabaseLookupOrphanContent(NcmContentMetaDatabase* db, bool* out_orphaned, size_t out_orphaned_size, const NcmNcaId* content_ids, size_t content_ids_size);
|
||||
Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db);
|
||||
Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u8* out);
|
||||
Result ncmContentMetaDatabaseHasContent(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key, const NcmNcaId* content_id);
|
||||
Result ncmContentMetaDatabaseListContentMetaInfo(NcmContentMetaDatabase* db, u32* out_entries_written, void* out_meta_info, size_t out_meta_info_size, const NcmContentMetaKey* key, u32 start_index);
|
||||
Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u8* out);
|
||||
Result ncmContentMetaDatabaseGetRequiredApplicationVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key); ///< [2.0.0+]
|
||||
Result ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type, u8 id_offset); ///< [5.0.0+]
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
/**
|
||||
* @file nifm.h
|
||||
* @brief Network interface service IPC wrapper.
|
||||
* @author shadowninja108, shibboleet, exelix
|
||||
* @author shadowninja108, shibboleet, exelix, yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../kernel/ipc.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
typedef enum {
|
||||
NifmServiceType_NotInitialized = 0, ///< Initializes nifm:u.
|
||||
@ -35,18 +35,27 @@ typedef enum {
|
||||
*/
|
||||
void nifmSetServiceType(NifmServiceType serviceType);
|
||||
|
||||
/// Initialize nifm. This is used automatically by \ref socketInitialize.
|
||||
Result nifmInitialize(void);
|
||||
|
||||
/// Exit nifm. This is used automatically by \ref socketExit.
|
||||
void nifmExit(void);
|
||||
|
||||
Result nifmGetCurrentIpAddress(u32* out);
|
||||
/// Gets the Service object for the actual nifm:* service session.
|
||||
Service* nifmGetServiceSession_StaticService(void);
|
||||
|
||||
Result nifmIsWirelessCommunicationEnabled(bool* out);
|
||||
/// Gets the Service object for IGeneralService.
|
||||
Service* nifmGetServiceSession_GeneralService(void);
|
||||
|
||||
Result nifmGetCurrentIpAddress(u32* out);
|
||||
|
||||
/**
|
||||
* @note Works only if called from nifm:a or nifm:s.
|
||||
*/
|
||||
Result nifmSetWirelessCommunicationEnabled(bool enable);
|
||||
|
||||
Result nifmIsWirelessCommunicationEnabled(bool* out);
|
||||
|
||||
/**
|
||||
* @note Will fail with 0xd46ed if Internet is neither connecting or connected (airplane mode or no known network in reach).
|
||||
* @param wifiStrength Strength of the Wi-Fi signal in number of bars from 0 to 3.
|
||||
|
||||
@ -1,101 +1,527 @@
|
||||
/**
|
||||
* @file ns.h
|
||||
* @brief NS service IPC wrapper.
|
||||
* @brief NS services IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../nacp.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/fs.h"
|
||||
#include "../services/ncm.h"
|
||||
#include "../services/async.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../kernel/tmem.h"
|
||||
|
||||
typedef struct {
|
||||
NacpStruct nacp;
|
||||
u8 icon[0x20000];//JPEG
|
||||
} NsApplicationControlData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 title_type;
|
||||
u8 storageID;
|
||||
u8 unk_x02;
|
||||
u8 padding;
|
||||
u32 title_version;
|
||||
u64 titleID;
|
||||
} NsApplicationContentMetaStatus;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 titleID;
|
||||
u8 type;
|
||||
u8 unk_x09;
|
||||
u8 unk_x0A[6];
|
||||
u8 unk_x10;
|
||||
u8 unk_x11[7];
|
||||
} NsApplicationRecord;
|
||||
|
||||
typedef struct {
|
||||
u64 titleID;
|
||||
u32 version;
|
||||
u8 storageID;
|
||||
u8 index;
|
||||
u8 is_application;
|
||||
} NsLaunchProperties;
|
||||
|
||||
/// ShellEvent
|
||||
typedef enum {
|
||||
NsShellEvent_None = 0,
|
||||
NsShellEvent_Exit = 1,
|
||||
NsShellEvent_Start = 2,
|
||||
NsShellEvent_Crash = 3,
|
||||
NsShellEvent_Debug = 4,
|
||||
NsShellEvent_None = 0, ///< None
|
||||
NsShellEvent_Exit = 1, ///< Exit
|
||||
NsShellEvent_Start = 2, ///< Start
|
||||
NsShellEvent_Crash = 3, ///< Crash
|
||||
NsShellEvent_Debug = 4, ///< Debug
|
||||
} NsShellEvent;
|
||||
|
||||
/// ApplicationControlSource
|
||||
typedef enum {
|
||||
NsApplicationControlSource_CacheOnly = 0, ///< Returns data from cache.
|
||||
NsApplicationControlSource_Storage = 1, ///< Returns data from storage if not present in cache.
|
||||
NsApplicationControlSource_StorageOnly = 2, ///< Returns data from storage without using cache.
|
||||
} NsApplicationControlSource;
|
||||
|
||||
/// BackgroundNetworkUpdateState
|
||||
typedef enum {
|
||||
NsBackgroundNetworkUpdateState_None = 0, ///< No sysupdate task exists.
|
||||
NsBackgroundNetworkUpdateState_Downloading = 1, ///< Sysupdate download in progress.
|
||||
NsBackgroundNetworkUpdateState_Ready = 2, ///< Sysupdate ready, pending install.
|
||||
} NsBackgroundNetworkUpdateState;
|
||||
|
||||
/// LatestSystemUpdate
|
||||
typedef enum {
|
||||
NsLatestSystemUpdate_Unknown0 = 0, ///< Unknown.
|
||||
NsLatestSystemUpdate_Unknown1 = 1, ///< Unknown.
|
||||
NsLatestSystemUpdate_Unknown2 = 2, ///< Unknown.
|
||||
} NsLatestSystemUpdate;
|
||||
|
||||
/// SystemUpdateControl
|
||||
typedef struct {
|
||||
NsShellEvent event;
|
||||
u64 process_id;
|
||||
Service s; ///< ISystemUpdateControl
|
||||
TransferMemory tmem; ///< TransferMemory for SetupCardUpdate/SetupCardUpdateViaSystemUpdater.
|
||||
} NsSystemUpdateControl;
|
||||
|
||||
/// ApplicationControlData
|
||||
typedef struct {
|
||||
NacpStruct nacp; ///< \ref NacpStruct
|
||||
u8 icon[0x20000]; ///< JPEG
|
||||
} NsApplicationControlData;
|
||||
|
||||
/// NsApplicationContentMetaStatus
|
||||
typedef struct {
|
||||
u8 title_type; ///< \ref NcmContentMetaType
|
||||
u8 storageID; ///< \ref FsStorageId
|
||||
u8 unk_x02; ///< Unknown.
|
||||
u8 padding; ///< Padding.
|
||||
u32 title_version; ///< Title version.
|
||||
u64 titleID; ///< titleID.
|
||||
} NsApplicationContentMetaStatus;
|
||||
|
||||
/// ApplicationRecord
|
||||
typedef struct {
|
||||
u64 titleID; ///< titleID.
|
||||
u8 type; ///< Type.
|
||||
u8 unk_x09; ///< Unknown.
|
||||
u8 unk_x0A[6]; ///< Unknown.
|
||||
u8 unk_x10; ///< Unknown.
|
||||
u8 unk_x11[7]; ///< Unknown.
|
||||
} NsApplicationRecord;
|
||||
|
||||
/// LaunchProperties
|
||||
typedef struct {
|
||||
u64 titleID; ///< titleID.
|
||||
u32 version; ///< Title version.
|
||||
u8 storageID; ///< \ref FsStorageId
|
||||
u8 index; ///< Index.
|
||||
u8 is_application; ///< Whether this is an Application.
|
||||
} NsLaunchProperties;
|
||||
|
||||
/// ShellEventInfo
|
||||
typedef struct {
|
||||
NsShellEvent event; ///< \ref NsShellEvent
|
||||
u64 process_id; ///< processID.
|
||||
} NsShellEventInfo;
|
||||
|
||||
/// SystemUpdateProgress. Commands which have this as output will return 0 with the output cleared, when no task is available.
|
||||
typedef struct {
|
||||
s64 current_size; ///< Current size. This value can be larger than total_size when the async operation is finishing. When total_size is <=0, this current_size field may contain a progress value for when the total_size is not yet determined.
|
||||
s64 total_size; ///< Total size, this field is only valid when >0.
|
||||
} NsSystemUpdateProgress;
|
||||
|
||||
/// EulaDataPath
|
||||
typedef struct {
|
||||
char path[0x100]; ///< Path.
|
||||
} NsEulaDataPath;
|
||||
|
||||
/// SystemDeliveryInfo
|
||||
typedef struct {
|
||||
u32 protocol_version; ///< Must be <= to and match a system-setting.
|
||||
u8 unk_x4[0x8]; ///< Unused by \ref nssuRequestSendSystemUpdate / \ref nssuControlRequestReceiveSystemUpdate, besides HMAC validation.
|
||||
u32 systemupdate_meta_version; ///< SystemUpdate meta version.
|
||||
u64 systemupdate_meta_titleid; ///< SystemUpdate meta titleID.
|
||||
u8 unk_x18; ///< Copied into state by \ref nssuRequestSendSystemUpdate.
|
||||
u8 unk_x19[0xc7]; ///< Unused by \ref nssuRequestSendSystemUpdate / \ref nssuControlRequestReceiveSystemUpdate, besides HMAC validation.
|
||||
u8 hmac[0x20]; ///< HMAC-SHA256 over the previous 0xe0-bytes.
|
||||
} NsSystemDeliveryInfo;
|
||||
|
||||
/// Default size for \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater. This is the size used by qlaunch for SetupCardUpdate.
|
||||
#define NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT 0x100000
|
||||
|
||||
///@name ns
|
||||
///@{
|
||||
|
||||
/// Initialize ns services. Uses ns:am on pre-3.0.0, ns:am2 on [3.0.0+].
|
||||
Result nsInitialize(void);
|
||||
|
||||
/// Exit ns services.
|
||||
void nsExit(void);
|
||||
|
||||
Result nsListApplicationRecord(NsApplicationRecord* buffer, size_t size, size_t entry_offset, size_t* out_entrycount);
|
||||
Result nsListApplicationContentMetaStatus(u64 titleID, u32 index, NsApplicationContentMetaStatus* buffer, size_t size, size_t* out_entrycount);
|
||||
Result nsGetApplicationControlData(u8 flag, u64 titleID, NsApplicationControlData* buffer, size_t size, size_t* actual_size);
|
||||
/// Gets the Service object for the actual ns:* service session. Only initialized on [3.0.0+], on pre-3.0.0 see \ref nsGetServiceSession_ApplicationManagerInterface.
|
||||
Service* nsGetServiceSession_GetterInterface(void);
|
||||
|
||||
/// Gets the Service object for IApplicationManagerInterface.
|
||||
Service* nsGetServiceSession_ApplicationManagerInterface(void);
|
||||
|
||||
/**
|
||||
* @brief Gets an listing of \ref NsApplicationRecord.
|
||||
* @param[out] records Output array of \ref NsApplicationRecord.
|
||||
* @param[in] count Size of the records array in entries.
|
||||
* @param[in] entry_offset Starting entry offset.
|
||||
* @param[out] out_entrycount Total output entries.
|
||||
*/
|
||||
Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entry_offset, s32* out_entrycount);
|
||||
|
||||
/**
|
||||
* @brief Gets an listing of \ref NsApplicationContentMetaStatus.
|
||||
* @param[in] titleID titleID.
|
||||
* @param[in] index Starting entry index.
|
||||
* @param[out] list Output array of \ref NsApplicationContentMetaStatus.
|
||||
* @param[in] count Size of the list array in entries.
|
||||
* @param[out] out_entrycount Total output entries.
|
||||
*/
|
||||
Result nsListApplicationContentMetaStatus(u64 titleID, s32 index, NsApplicationContentMetaStatus* list, s32 count, s32* out_entrycount);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref NsApplicationControlData for the specified title.
|
||||
* @param[in] flag Flag, official sw uses value 1.
|
||||
* @param[in] titleID titleID.
|
||||
* @param[out] buffer \ref NsApplicationControlData
|
||||
* @param[in] size Size of the buffer.
|
||||
* @param[out] actual_size Actual output size.
|
||||
*/
|
||||
Result nsGetApplicationControlData(NsApplicationControlSource source, u64 titleID, NsApplicationControlData* buffer, size_t size, u64* actual_size);
|
||||
|
||||
/**
|
||||
* @brief Returns the total storage capacity (used + free) from content manager services.
|
||||
* @param storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
|
||||
* @param size Pointer to output the total storage size to.
|
||||
* @param[in] storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
|
||||
* @param[out] size Pointer to output the total storage size to.
|
||||
*/
|
||||
Result nsGetTotalSpaceSize(FsStorageId storage_id, u64 *size);
|
||||
|
||||
/**
|
||||
* @brief Returns the available storage capacity from content manager services.
|
||||
* @param storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
|
||||
* @param size Pointer to output the free storage size to.
|
||||
* @param[in] storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
|
||||
* @param[out] size Pointer to output the free storage size to.
|
||||
*/
|
||||
Result nsGetFreeSpaceSize(FsStorageId storage_id, u64 *size);
|
||||
|
||||
///@}
|
||||
|
||||
///@name ns:vm
|
||||
///@{
|
||||
|
||||
/// Initialize ns:vm. On pre-3.0.0 this must be used with \ref nsInitialize.
|
||||
Result nsvmInitialize(void);
|
||||
|
||||
/// Exit ns:vm.
|
||||
void nsvmExit(void);
|
||||
|
||||
Result nsvmNeedsUpdateVulnerability(bool *out);
|
||||
Result nsvmGetSafeSystemVersion(u16 *out);
|
||||
/// Gets the Service object for ns:vm. This is only initialized on [3.0.0+].
|
||||
Service* nsvmGetServiceSession(void);
|
||||
|
||||
/* ns:dev */
|
||||
Result nsvmNeedsUpdateVulnerability(bool *out);
|
||||
Result nsvmGetSafeSystemVersion(NcmContentMetaKey *out); ///< [4.0.0+]
|
||||
|
||||
///@}
|
||||
|
||||
///@name ns:dev
|
||||
///@{
|
||||
|
||||
/// Initialize ns:dev.
|
||||
Result nsdevInitialize(void);
|
||||
|
||||
/// Initialize ns:dev.
|
||||
void nsdevExit(void);
|
||||
|
||||
/// Gets the Service object for ns:dev.
|
||||
Service* nsdevGetServiceSession(void);
|
||||
|
||||
Result nsdevLaunchProgram(u64* out_pid, const NsLaunchProperties* properties, u32 flags);
|
||||
Result nsdevTerminateProcess(u64 pid);
|
||||
Result nsdevTerminateProgram(u64 tid);
|
||||
Result nsdevGetShellEvent(Event* out); // Autoclear for nsdevShellEvent is always true.
|
||||
Result nsdevGetShellEvent(Event* out_event); ///< Autoclear for nsdevShellEvent is always true.
|
||||
Result nsdevGetShellEventInfo(NsShellEventInfo* out);
|
||||
Result nsdevTerminateApplication(void);
|
||||
Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len);
|
||||
Result nsdevLaunchApplication(u64* out_pid, u64 app_title_id, u32 flags);
|
||||
Result nsdevLaunchApplicationWithStorageId(u64* out_pid, u64 app_title_id, u32 flags, u8 app_storage_id, u8 patch_storage_id);
|
||||
Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out);
|
||||
Result nsdevGetRunningApplicationProcessId(u64* out_pid);
|
||||
Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActive(bool can_be_active);
|
||||
Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 app_title_id, u32 flags);
|
||||
Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 app_title_id, u32 flags, u8 app_storage_id, u8 patch_storage_id);
|
||||
Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out); ///< [6.0.0-8.1.0]
|
||||
Result nsdevGetRunningApplicationProcessIdForDevelop(u64* out_pid); ///< [6.0.0+]
|
||||
Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop(bool can_be_active); ///< [6.0.0+]
|
||||
|
||||
///@}
|
||||
|
||||
///@name ns:su
|
||||
///@{
|
||||
|
||||
/// Initialize ns:su.
|
||||
Result nssuInitialize(void);
|
||||
|
||||
/// Exit ns:su.
|
||||
void nssuExit(void);
|
||||
|
||||
/// Gets the Service object for ns:su.
|
||||
Service* nssuGetServiceSession(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the \ref NsBackgroundNetworkUpdateState.
|
||||
* @note Internally this uses nim commands ListSystemUpdateTask and GetSystemUpdateTaskInfo to determine the output state.
|
||||
* @param[out] out \ref NsBackgroundNetworkUpdateState
|
||||
*/
|
||||
Result nssuGetBackgroundNetworkUpdateState(NsBackgroundNetworkUpdateState *out);
|
||||
|
||||
/**
|
||||
* @brief Opens a \ref NsSystemUpdateControl.
|
||||
* @note Only 1 \ref NsSystemUpdateControl can be open at a time.
|
||||
* @param[out] c \ref NsSystemUpdateControl
|
||||
*/
|
||||
Result nssuOpenSystemUpdateControl(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief Uses nim ListSystemUpdateTask, then uses the task with DestroySystemUpdateTask if it exists. Then this runs ExFat handling, updates state, and sets the same state flag as \ref nssuRequestBackgroundNetworkUpdate.
|
||||
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
|
||||
*/
|
||||
Result nssuNotifyExFatDriverRequired(void);
|
||||
|
||||
/**
|
||||
* @brief ClearExFatDriverStatusForDebug
|
||||
*/
|
||||
Result nssuClearExFatDriverStatusForDebug(void);
|
||||
|
||||
/**
|
||||
* @brief RequestBackgroundNetworkUpdate
|
||||
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
|
||||
*/
|
||||
Result nssuRequestBackgroundNetworkUpdate(void);
|
||||
|
||||
/**
|
||||
* @brief This checks whether a sysupdate is needed with the input \ref NcmContentMetaKey using NCM commands, if not this will just return 0. Otherwise, this will then run code which is identical to \ref nssuRequestBackgroundNetworkUpdate.
|
||||
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
|
||||
* @param[in] key \ref NcmContentMetaKey
|
||||
*/
|
||||
Result nssuNotifyBackgroundNetworkUpdate(const NcmContentMetaKey *key);
|
||||
|
||||
/**
|
||||
* @brief NotifyExFatDriverDownloadedForDebug
|
||||
*/
|
||||
Result nssuNotifyExFatDriverDownloadedForDebug(void);
|
||||
|
||||
/**
|
||||
* @brief Gets an Event which can be signaled by \ref nssuNotifySystemUpdateForContentDelivery.
|
||||
* @note The Event must be closed by the user once finished with it.
|
||||
* @param[out] out_event Output Event with autoclear=false.
|
||||
*/
|
||||
Result nssuGetSystemUpdateNotificationEventForContentDelivery(Event* out_event);
|
||||
|
||||
/**
|
||||
* @brief Signals the event returned by \ref nssuGetSystemUpdateNotificationEventForContentDelivery.
|
||||
*/
|
||||
Result nssuNotifySystemUpdateForContentDelivery(void);
|
||||
|
||||
/**
|
||||
* @brief This does shutdown preparation.
|
||||
* @note This is used by am-sysmodule, so generally there's no need to use this.
|
||||
* @note Only available on [3.0.0+].
|
||||
*/
|
||||
Result nssuPrepareShutdown(void);
|
||||
|
||||
/**
|
||||
* @brief This uses nim ListSystemUpdateTask, then when a task is returned uses it with DestroySystemUpdateTask.
|
||||
* @note Only available on [4.0.0+].
|
||||
*/
|
||||
Result nssuDestroySystemUpdateTask(void);
|
||||
|
||||
/**
|
||||
* @brief RequestSendSystemUpdate
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param[out] a \ref AsyncResult
|
||||
* @param[in] inval0 Unknown input value.
|
||||
* @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556).
|
||||
* @param[in] info \ref NsSystemDeliveryInfo
|
||||
*/
|
||||
Result nssuRequestSendSystemUpdate(AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info);
|
||||
|
||||
/**
|
||||
* @brief GetSendSystemUpdateProgress
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param[out] out \ref NsSystemUpdateProgress
|
||||
*/
|
||||
Result nssuGetSendSystemUpdateProgress(NsSystemUpdateProgress *out);
|
||||
|
||||
///@}
|
||||
|
||||
///@name ISystemUpdateControl
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Close a \ref NsSystemUpdateControl.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
*/
|
||||
void nssuControlClose(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief Gets whether a network sysupdate was downloaded, with install pending.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out Output flag.
|
||||
*/
|
||||
Result nssuControlHasDownloaded(NsSystemUpdateControl *c, bool* out);
|
||||
|
||||
/**
|
||||
* @brief RequestCheckLatestUpdate
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] a \ref AsyncValue. The data that can be read from this is u8 \ref NsLatestSystemUpdate.
|
||||
*/
|
||||
Result nssuControlRequestCheckLatestUpdate(NsSystemUpdateControl *c, AsyncValue *a);
|
||||
|
||||
/**
|
||||
* @brief RequestDownloadLatestUpdate
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] a \ref AsyncResult
|
||||
*/
|
||||
Result nssuControlRequestDownloadLatestUpdate(NsSystemUpdateControl *c, AsyncResult *a);
|
||||
|
||||
/**
|
||||
* @brief GetDownloadProgress
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out \ref NsSystemUpdateProgress
|
||||
*/
|
||||
Result nssuControlGetDownloadProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
|
||||
|
||||
/**
|
||||
* @brief ApplyDownloadedUpdate
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
*/
|
||||
Result nssuControlApplyDownloadedUpdate(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief RequestPrepareCardUpdate
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] a \ref AsyncResult
|
||||
*/
|
||||
Result nssuControlRequestPrepareCardUpdate(NsSystemUpdateControl *c, AsyncResult *a);
|
||||
|
||||
/**
|
||||
* @brief GetPrepareCardUpdateProgress
|
||||
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out \ref NsSystemUpdateProgress
|
||||
*/
|
||||
Result nssuControlGetPrepareCardUpdateProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
|
||||
|
||||
/**
|
||||
* @brief HasPreparedCardUpdate
|
||||
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out Output flag.
|
||||
*/
|
||||
Result nssuControlHasPreparedCardUpdate(NsSystemUpdateControl *c, bool* out);
|
||||
|
||||
/**
|
||||
* @brief ApplyCardUpdate
|
||||
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
*/
|
||||
Result nssuControlApplyCardUpdate(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief Gets the filesize for the specified DownloadedEulaData.
|
||||
* @note This mounts the Eula title, then uses the file "<mountname>:/<input path>".
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetDownloadedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief Gets the specified DownloadedEulaData.
|
||||
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] buffer Output buffer.
|
||||
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetDownloadedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief SetupCardUpdate
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated.
|
||||
* @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT.
|
||||
*/
|
||||
Result nssuControlSetupCardUpdate(NsSystemUpdateControl *c, void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Gets the filesize for the specified PreparedCardUpdateEulaData.
|
||||
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetPreparedCardUpdateEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief Gets the specified PreparedCardUpdateEulaData.
|
||||
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] buffer Output buffer.
|
||||
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetPreparedCardUpdateEulaDataSize.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetPreparedCardUpdateEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief SetupCardUpdateViaSystemUpdater
|
||||
* @note Same as \ref nssuControlSetupCardUpdate, except this doesn't run the code for fs cmds GetGameCardHandle/GetGameCardUpdatePartitionInfo, and uses fs OpenRegisteredUpdatePartition instead of OpenGameCardFileSystem.
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated.
|
||||
* @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT.
|
||||
*/
|
||||
Result nssuControlSetupCardUpdateViaSystemUpdater(NsSystemUpdateControl *c, void* buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief HasReceived
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out Output flag.
|
||||
*/
|
||||
Result nssuControlHasReceived(NsSystemUpdateControl *c, bool* out);
|
||||
|
||||
/**
|
||||
* @brief RequestReceiveSystemUpdate
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] a \ref AsyncResult
|
||||
* @param[in] inval0 Unknown input value.
|
||||
* @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556).
|
||||
* @param[in] info \ref NsSystemDeliveryInfo
|
||||
*/
|
||||
Result nssuControlRequestReceiveSystemUpdate(NsSystemUpdateControl *c, AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info);
|
||||
|
||||
/**
|
||||
* @brief GetReceiveProgress
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] out \ref NsSystemUpdateProgress
|
||||
*/
|
||||
Result nssuControlGetReceiveProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
|
||||
|
||||
/**
|
||||
* @brief ApplyReceivedUpdate
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
*/
|
||||
Result nssuControlApplyReceivedUpdate(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief Gets the filesize for the specified ReceivedEulaData.
|
||||
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetReceivedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief Gets the specified ReceivedEulaData.
|
||||
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[in] path EulaData path.
|
||||
* @param[out] buffer Output buffer.
|
||||
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetReceivedEulaDataSize.
|
||||
* @param[out] filesize Output filesize.
|
||||
*/
|
||||
Result nssuControlGetReceivedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
|
||||
|
||||
/**
|
||||
* @brief Does setup for ReceiveSystemUpdate by using the same nim cmds as \ref nssuDestroySystemUpdateTask.
|
||||
* @note Only available on [4.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
*/
|
||||
Result nssuControlSetupToReceiveSystemUpdate(NsSystemUpdateControl *c);
|
||||
|
||||
/**
|
||||
* @brief RequestCheckLatestUpdateIncludesRebootlessUpdate
|
||||
* @note Only available on [6.0.0+].
|
||||
* @param c \ref NsSystemUpdateControl
|
||||
* @param[out] a \ref AsyncValue
|
||||
*/
|
||||
Result nssuControlRequestCheckLatestUpdateIncludesRebootlessUpdate(NsSystemUpdateControl *c, AsyncValue *a);
|
||||
|
||||
///@}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../kernel/event.h"
|
||||
|
||||
Result nvInitialize(void);
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// LaunchFlag
|
||||
typedef enum {
|
||||
@ -79,10 +79,10 @@ Service* pmbmGetServiceSession(void);
|
||||
Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids);
|
||||
Result pmdmntStartProcess(u64 pid);
|
||||
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id);
|
||||
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id);
|
||||
Result pmdmntEnableDebugForTitleId(Event* out, u64 title_id);
|
||||
Result pmdmntGetApplicationPid(u64* pid_out);
|
||||
Result pmdmntEnableDebugForApplication(Handle* handle_out);
|
||||
Result pmdmntDisableDebug(void);
|
||||
Result pmdmntEnableDebugForApplication(Event* out);
|
||||
Result pmdmntDisableDebug(u32 which);
|
||||
|
||||
Result pminfoGetTitleId(u64* title_id_out, u64 pid);
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../kernel/event.h"
|
||||
|
||||
typedef enum {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
#include "../services/ldr.h"
|
||||
|
||||
Result ldrRoInitialize(void);
|
||||
|
||||
@ -7,37 +7,39 @@
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../result.h"
|
||||
#include "../types.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
#define SET_MAX_NAME_SIZE 0x48
|
||||
#define SET_MAX_NICKNAME_SIZE 0x80
|
||||
|
||||
typedef enum {
|
||||
ColorSetId_Light=0,
|
||||
ColorSetId_Dark=1
|
||||
ColorSetId_Light = 0,
|
||||
ColorSetId_Dark = 1,
|
||||
} ColorSetId;
|
||||
|
||||
/// IDs for Language.
|
||||
typedef enum
|
||||
{
|
||||
SetLanguage_JA = 0, ///< Japanese
|
||||
SetLanguage_ENUS = 1, ///< US English ("AmericanEnglish")
|
||||
SetLanguage_FR = 2, ///< French
|
||||
SetLanguage_DE = 3, ///< German
|
||||
SetLanguage_IT = 4, ///< Italian
|
||||
SetLanguage_ES = 5, ///< Spanish
|
||||
SetLanguage_ZHCN = 6, ///< Simplified Chinese ("Chinese")
|
||||
SetLanguage_KO = 7, ///< Korean
|
||||
SetLanguage_NL = 8, ///< Dutch
|
||||
SetLanguage_PT = 9, ///< Portuguese
|
||||
SetLanguage_RU = 10, ///< Russian
|
||||
SetLanguage_ZHTW = 11, ///< Traditional Chinese ("Taiwanese")
|
||||
SetLanguage_ENGB = 12, ///< GB English ("BritishEnglish")
|
||||
SetLanguage_FRCA = 13, ///< CA French ("CanadianFrench")
|
||||
SetLanguage_ES419 = 14, ///< "LatinAmericanSpanish"
|
||||
SetLanguage_Total, ///< Total languages supported by this enum.
|
||||
SetLanguage_JA = 0, ///< Japanese
|
||||
SetLanguage_ENUS = 1, ///< US English ("AmericanEnglish")
|
||||
SetLanguage_FR = 2, ///< French
|
||||
SetLanguage_DE = 3, ///< German
|
||||
SetLanguage_IT = 4, ///< Italian
|
||||
SetLanguage_ES = 5, ///< Spanish
|
||||
SetLanguage_ZHCN = 6, ///< Simplified Chinese ("Chinese")
|
||||
SetLanguage_KO = 7, ///< Korean
|
||||
SetLanguage_NL = 8, ///< Dutch
|
||||
SetLanguage_PT = 9, ///< Portuguese
|
||||
SetLanguage_RU = 10, ///< Russian
|
||||
SetLanguage_ZHTW = 11, ///< Traditional Chinese ("Taiwanese")
|
||||
SetLanguage_ENGB = 12, ///< GB English ("BritishEnglish")
|
||||
SetLanguage_FRCA = 13, ///< CA French ("CanadianFrench")
|
||||
SetLanguage_ES419 = 14, ///< "LatinAmericanSpanish"
|
||||
SetLanguage_ZHHANS = 15, ///< [4.0.0+] ChineseSimplified
|
||||
SetLanguage_ZHHANT = 16, ///< [4.0.0+] ChineseTraditional
|
||||
SetLanguage_Total, ///< Total languages supported by this enum.
|
||||
} SetLanguage;
|
||||
|
||||
/// Region codes.
|
||||
@ -46,27 +48,30 @@ typedef enum {
|
||||
SetRegion_USA = 1, ///< The Americas
|
||||
SetRegion_EUR = 2, ///< Europe
|
||||
SetRegion_AUS = 3, ///< Australia/New Zealand
|
||||
SetRegion_CHN = 4, ///< China
|
||||
SetRegion_KOR = 5, ///< Korea
|
||||
SetRegion_TWN = 6, ///< Taiwan
|
||||
} SetRegion;
|
||||
|
||||
/// Command IDs for setsysGetFlag/setsysSetFlag.
|
||||
typedef enum {
|
||||
SetSysFlag_LockScreen = 7,
|
||||
SetSysFlag_ConsoleInformationUpload = 25,
|
||||
SetSysFlag_LockScreen = 7,
|
||||
SetSysFlag_ConsoleInformationUpload = 25,
|
||||
SetSysFlag_AutomaticApplicationDownload = 27,
|
||||
SetSysFlag_Quest = 47,
|
||||
SetSysFlag_Usb30Enable = 65,
|
||||
SetSysFlag_NfcEnable = 69,
|
||||
SetSysFlag_WirelessLanEnable = 73,
|
||||
SetSysFlag_BluetoothEnable = 88,
|
||||
SetSysFlag_AutoUpdateEnable = 95,
|
||||
SetSysFlag_BatteryPercentage = 99,
|
||||
SetSysFlag_ExternalRtcReset = 101,
|
||||
SetSysFlag_UsbFullKeyEnable = 103,
|
||||
SetSysFlag_BluetoothAfhEnable = 111,
|
||||
SetSysFlag_BluetoothBoostEnable = 113,
|
||||
SetSysFlag_InRepairProcessEnable = 115,
|
||||
SetSysFlag_HeadphoneVolumeUpdate = 117,
|
||||
SetSysFlag_RequiresRunRepairTimeReviser = 141,
|
||||
SetSysFlag_Quest = 47,
|
||||
SetSysFlag_Usb30Enable = 65,
|
||||
SetSysFlag_NfcEnable = 69,
|
||||
SetSysFlag_WirelessLanEnable = 73,
|
||||
SetSysFlag_BluetoothEnable = 88,
|
||||
SetSysFlag_AutoUpdateEnable = 95, ///< [2.0.0+]
|
||||
SetSysFlag_BatteryPercentage = 99, ///< [2.0.0+]
|
||||
SetSysFlag_ExternalRtcReset = 101, ///< [2.0.0+]
|
||||
SetSysFlag_UsbFullKeyEnable = 103, ///< [3.0.0+]
|
||||
SetSysFlag_BluetoothAfhEnable = 111, ///< [3.0.0+]
|
||||
SetSysFlag_BluetoothBoostEnable = 113, ///< [3.0.0+]
|
||||
SetSysFlag_InRepairProcessEnable = 115, ///< [3.0.0+]
|
||||
SetSysFlag_HeadphoneVolumeUpdate = 117, ///< [3.0.0+]
|
||||
SetSysFlag_RequiresRunRepairTimeReviser = 141, ///< [5.0.0+]
|
||||
} SetSysFlag;
|
||||
|
||||
/// Structure returned by \ref setsysGetFirmwareVersion
|
||||
@ -89,11 +94,11 @@ Result setInitialize(void);
|
||||
void setExit(void);
|
||||
Service* setGetServiceSession(void);
|
||||
|
||||
/// Converts LanguageCode to Language.
|
||||
Result setMakeLanguage(u64 LanguageCode, s32 *Language);
|
||||
/// Converts LanguageCode to \ref SetLanguage.
|
||||
Result setMakeLanguage(u64 LanguageCode, SetLanguage *Language);
|
||||
|
||||
/// Converts Language to LanguageCode.
|
||||
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode);
|
||||
/// Converts \ref SetLanguage to LanguageCode.
|
||||
Result setMakeLanguageCode(SetLanguage Language, u64 *LanguageCode);
|
||||
|
||||
/// Gets the current system LanguageCode.
|
||||
/// Normally this should be used instead of \ref setGetLanguageCode.
|
||||
@ -138,8 +143,9 @@ Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u6
|
||||
* @param item_key Item key string.
|
||||
* @param value_out Pointer to output the value to.
|
||||
* @param value_out_size Size of the value_out buffer.
|
||||
* @param size_out Total size which was copied to value_out.
|
||||
*/
|
||||
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size);
|
||||
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size, u64 *size_out);
|
||||
|
||||
/**
|
||||
* @brief Gets the system's serial number.
|
||||
@ -169,9 +175,9 @@ Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out);
|
||||
|
||||
/**
|
||||
* @brief Gets an event that settings will signal on flag change.
|
||||
* @param out Event to bind. Output event will have autoclear=false.
|
||||
* @param out_event Event to bind. Output event will have autoclear=false.
|
||||
*/
|
||||
Result setsysBindFatalDirtyFlagEvent(Event *out);
|
||||
Result setsysBindFatalDirtyFlagEvent(Event *out_event);
|
||||
|
||||
/**
|
||||
* @brief Gets the settings flags that have changed.
|
||||
|
||||
@ -9,67 +9,10 @@
|
||||
#include "../types.h"
|
||||
#include "../kernel/svc.h"
|
||||
#include "../kernel/ipc.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// Service type.
|
||||
typedef enum {
|
||||
ServiceType_Uninitialized, ///< Uninitialized service.
|
||||
ServiceType_Normal, ///< Normal service.
|
||||
ServiceType_Domain, ///< Domain.
|
||||
ServiceType_DomainSubservice, ///< Domain subservice;
|
||||
ServiceType_Override, ///< Service overriden in the homebrew environment.
|
||||
} ServiceType;
|
||||
|
||||
/// Service object structure.
|
||||
typedef struct {
|
||||
Handle handle;
|
||||
u32 object_id;
|
||||
ServiceType type;
|
||||
} Service;
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is overriden in the homebrew environment.
|
||||
* @param[in] s Service object.
|
||||
* @return true if overriden.
|
||||
*/
|
||||
static inline bool serviceIsOverride(Service* s) {
|
||||
return s->type == ServiceType_Override;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service has been initialized.
|
||||
* @param[in] s Service object.
|
||||
* @return true if initialized.
|
||||
*/
|
||||
static inline bool serviceIsActive(Service* s) {
|
||||
return s->type != ServiceType_Uninitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is a domain.
|
||||
* @param[in] s Service object.
|
||||
* @return true if a domain.
|
||||
*/
|
||||
static inline bool serviceIsDomain(Service* s) {
|
||||
return s->type == ServiceType_Domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is a domain subservice.
|
||||
* @param[in] s Service object.
|
||||
* @return true if a domain subservice.
|
||||
*/
|
||||
static inline bool serviceIsDomainSubservice(Service* s) {
|
||||
return s->type == ServiceType_DomainSubservice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For a domain/domain subservice, return the associated object ID.
|
||||
* @param[in] s Service object, necessarily a domain or domain subservice.
|
||||
* @return The object ID.
|
||||
*/
|
||||
static inline u32 serviceGetObjectId(Service* s) {
|
||||
return s->object_id;
|
||||
}
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
/**
|
||||
* @brief Closes a domain object by ID.
|
||||
@ -77,8 +20,9 @@ static inline u32 serviceGetObjectId(Service* s) {
|
||||
* @param object_id ID of the object to close.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
||||
return ipcCloseObjectById(s->handle, object_id);
|
||||
return ipcCloseObjectById(s->session, object_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,31 +30,9 @@ static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
||||
* @param[in] s Service object.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result serviceIpcDispatch(Service* s) {
|
||||
return ipcDispatch(s->handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a service object from an IPC session handle.
|
||||
* @param[out] s Service object.
|
||||
* @param[in] h IPC session handle.
|
||||
*/
|
||||
static inline void serviceCreate(Service* s, Handle h) {
|
||||
s->handle = h;
|
||||
s->type = ServiceType_Normal;
|
||||
s->object_id = IPC_INVALID_OBJECT_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a domain subservice object from a parent service.
|
||||
* @param[out] s Service object.
|
||||
* @param[in] parent Parent service, necessarily a domain or domain subservice.
|
||||
* @param[in] object_id Object ID for this subservice.
|
||||
*/
|
||||
static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id) {
|
||||
s->handle = parent->handle;
|
||||
s->type = ServiceType_DomainSubservice;
|
||||
s->object_id = object_id;
|
||||
return ipcDispatch(s->session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,6 +42,7 @@ static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u3
|
||||
* @param[in] r Parsed IPC command containing handles/object IDs to create subservice from.
|
||||
* @param[in] i The index of the handle/object ID to create subservice from.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParsedCommand* r, int i) {
|
||||
if (r->IsDomainResponse) {
|
||||
return serviceCreateDomainSubservice(s, parent, r->OutObjectIds[i]);
|
||||
@ -133,63 +56,13 @@ static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParse
|
||||
* @param[in] s Service object to send.
|
||||
* @param[in] cmd IPC command structure.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void serviceSendObject(Service* s, IpcCommand* cmd) {
|
||||
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
||||
ipcSendObjectId(cmd, s->object_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a regular service to a domain.
|
||||
* @param[in] s Service object.
|
||||
* @return Result code.
|
||||
*/
|
||||
static inline Result serviceConvertToDomain(Service* s) {
|
||||
Result rc = 0;
|
||||
if (serviceIsOverride(s)) {
|
||||
rc = ipcCloneSession(s->handle, 1, &s->handle);
|
||||
if (R_FAILED(rc)) {
|
||||
return rc;
|
||||
}
|
||||
s->type = ServiceType_Normal;
|
||||
}
|
||||
rc = ipcConvertSessionToDomain(s->handle, &s->object_id);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
s->type = ServiceType_Domain;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes a service.
|
||||
* @param[in] s Service object.
|
||||
*/
|
||||
static inline void serviceClose(Service* s) {
|
||||
switch (s->type) {
|
||||
|
||||
case ServiceType_Normal:
|
||||
case ServiceType_Domain:
|
||||
ipcCloseSession(s->handle);
|
||||
svcCloseHandle(s->handle);
|
||||
break;
|
||||
|
||||
case ServiceType_DomainSubservice:
|
||||
serviceCloseObjectById(s, s->object_id);
|
||||
break;
|
||||
|
||||
case ServiceType_Override:
|
||||
// Don't close because we don't own the overridden handle.
|
||||
break;
|
||||
|
||||
case ServiceType_Uninitialized:
|
||||
break;
|
||||
}
|
||||
|
||||
s->type = ServiceType_Uninitialized;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Prepares the header of an IPC command structure for a service.
|
||||
* @param s Service to prepare message header for
|
||||
@ -197,6 +70,7 @@ static inline void serviceClose(Service* s) {
|
||||
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
|
||||
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t sizeof_raw) {
|
||||
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
||||
return ipcPrepareHeaderForDomain(cmd, sizeof_raw, serviceGetObjectId(s));
|
||||
@ -212,6 +86,7 @@ static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t
|
||||
* @param sizeof_raw Size in bytes of the raw data structure.
|
||||
* @return Result code.
|
||||
*/
|
||||
DEPRECATED
|
||||
static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t sizeof_raw) {
|
||||
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
||||
return ipcParseDomainResponse(r, sizeof_raw);
|
||||
@ -220,6 +95,8 @@ static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t siz
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/**
|
||||
* @brief Initializes SM.
|
||||
* @return Result code.
|
||||
@ -274,12 +151,6 @@ Result smRegisterService(Handle* handle_out, const char* name, bool is_light, in
|
||||
*/
|
||||
Result smUnregisterService(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Check whether SM is initialized.
|
||||
* @return true if initialized.
|
||||
*/
|
||||
bool smHasInitialized(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the Service session used to communicate with SM.
|
||||
* @return Pointer to service session used to communicate with SM.
|
||||
@ -291,7 +162,13 @@ Service *smGetServiceSession(void);
|
||||
* @param[in] name Name of the service.
|
||||
* @return Encoded name.
|
||||
*/
|
||||
u64 smEncodeName(const char* name);
|
||||
NX_CONSTEXPR u64 smEncodeName(const char* name)
|
||||
{
|
||||
u64 name_encoded = 0;
|
||||
for (unsigned i = 0; name[i] && i < 8; i ++)
|
||||
name_encoded |= ((u64) name[i]) << (8*i);
|
||||
return name_encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overrides a service with a custom IPC service handle.
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../kernel/event.h"
|
||||
|
||||
#define SPL_RSA_BUFFER_SIZE (0x100)
|
||||
|
||||
@ -74,7 +75,7 @@ Result splCryptoCryptAesCtr(const void *input, void *output, size_t size, u32 ke
|
||||
Result splCryptoComputeCmac(const void *input, size_t size, u32 keyslot, void *out_cmac);
|
||||
Result splCryptoLockAesEngine(u32 *out_keyslot);
|
||||
Result splCryptoUnlockAesEngine(u32 keyslot);
|
||||
Result splCryptoGetSecurityEngineEvent(Handle *out_event);
|
||||
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);
|
||||
|
||||
@ -86,6 +87,8 @@ Result splEsUnwrapRsaOaepWrappedTitlekey(const void *rsa_wrapped_titlekey, const
|
||||
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 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);
|
||||
|
||||
Result splFsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version);
|
||||
Result splFsSecureExpMod(const void *input, const void *modulus, void *dst);
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// Time clock type.
|
||||
typedef enum {
|
||||
@ -28,11 +28,11 @@ typedef struct {
|
||||
} TimeCalendarTime;
|
||||
|
||||
typedef struct {
|
||||
u32 wday; ///< 0-based day-of-week.
|
||||
u32 yday; ///< 0-based day-of-year.
|
||||
char timezoneName[8]; ///< Timezone name string.
|
||||
u32 DST; ///< 0 = no DST, 1 = DST.
|
||||
s32 offset; ///< Seconds relative to UTC for this timezone.
|
||||
u32 wday; ///< 0-based day-of-week.
|
||||
u32 yday; ///< 0-based day-of-year.
|
||||
char timezoneName[8]; ///< Timezone name string.
|
||||
u32 DST; ///< 0 = no DST, 1 = DST.
|
||||
s32 offset; ///< Seconds relative to UTC for this timezone.
|
||||
} TimeCalendarAdditionalInfo;
|
||||
|
||||
typedef struct {
|
||||
@ -43,11 +43,27 @@ typedef struct {
|
||||
char name[0x24];
|
||||
} TimeLocationName;
|
||||
|
||||
/// Initialize time. Used automatically during app startup.
|
||||
Result timeInitialize(void);
|
||||
|
||||
/// Exit time. Used automatically during app startup.
|
||||
void timeExit(void);
|
||||
|
||||
/// Gets the Service object for the actual time service session.
|
||||
Service* timeGetServiceSession(void);
|
||||
|
||||
/// Gets the Service object for ISystemClock with the specified \ref TimeType. This will return NULL when the type is invalid.
|
||||
Service* timeGetServiceSession_SystemClock(TimeType type);
|
||||
|
||||
/// Gets the Service object for ITimeZoneService.
|
||||
Service* timeGetServiceSession_TimeZoneService(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the time for the specified clock.
|
||||
* @param[in] type Clock to use.
|
||||
* @param[out] timestamp POSIX UTC timestamp.
|
||||
* @return Result code.
|
||||
*/
|
||||
Result timeGetCurrentTime(TimeType type, u64 *timestamp);
|
||||
|
||||
/**
|
||||
@ -60,13 +76,13 @@ Result timeSetCurrentTime(TimeType type, u64 timestamp);
|
||||
|
||||
Result timeGetDeviceLocationName(TimeLocationName *name);
|
||||
Result timeSetDeviceLocationName(const TimeLocationName *name);
|
||||
Result timeGetTotalLocationNameCount(u32 *total_location_name_count);
|
||||
Result timeLoadLocationNameList(u32 index, TimeLocationName *location_name_array, size_t location_name_size, u32 *location_name_count);
|
||||
Result timeGetTotalLocationNameCount(s32 *total_location_name_count);
|
||||
Result timeLoadLocationNameList(s32 index, TimeLocationName *location_name_array, s32 location_name_max, s32 *location_name_count);
|
||||
|
||||
Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule);
|
||||
|
||||
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count);
|
||||
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count);
|
||||
Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info);
|
||||
Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info);
|
||||
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count);
|
||||
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count);
|
||||
|
||||
|
||||
47
nx/include/switch/services/ts.h
Normal file
47
nx/include/switch/services/ts.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file ts.h
|
||||
* @brief Temperature measurement (ts) service IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// Location
|
||||
typedef enum {
|
||||
TsLocation_Internal = 0, ///< Internal
|
||||
TsLocation_External = 1, ///< External
|
||||
} TsLocation;
|
||||
|
||||
/// Initialize ts.
|
||||
Result tsInitialize(void);
|
||||
|
||||
/// Exit ts.
|
||||
void tsExit(void);
|
||||
|
||||
/// Gets the Service for ts.
|
||||
Service* tsGetServiceSession(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the min/max temperature for the specified \ref TsLocation.
|
||||
* @param[in] location \ref TsLocation
|
||||
* @param[out] min_temperature Output minimum temperature in Celsius.
|
||||
* @param[out] max_temperature Output maximum temperature in Celsius.
|
||||
*/
|
||||
Result tsGetTemperatureRange(TsLocation location, s32 *min_temperature, s32 *max_temperature);
|
||||
|
||||
/**
|
||||
* @brief Gets the temperature for the specified \ref TsLocation.
|
||||
* @param[in] location \ref TsLocation
|
||||
* @param[out] temperature Output temperature in Celsius.
|
||||
*/
|
||||
Result tsGetTemperature(TsLocation location, s32 *temperature);
|
||||
|
||||
/**
|
||||
* @brief Gets the temperature for the specified \ref TsLocation, in MilliC.
|
||||
* @param[in] location \ref TsLocation
|
||||
* @param[out] temperature Output temperature in MilliC.
|
||||
*/
|
||||
Result tsGetTemperatureMilliC(TsLocation location, s32 *temperature);
|
||||
|
||||
@ -96,7 +96,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
Service s;
|
||||
Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
|
||||
size_t ptrbufsize; ///< [3.0.0+] IPC pointer buffer size.
|
||||
|
||||
struct usb_endpoint_descriptor desc;
|
||||
} UsbHsClientEpSession;
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
/**
|
||||
* @file wlaninf.h
|
||||
* @brief WLAN InfraManager service IPC wrapper.
|
||||
* @author natinusala
|
||||
* @author natinusala, yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../kernel/ipc.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../types.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
/// WLAN State.
|
||||
typedef enum {
|
||||
@ -20,6 +20,7 @@ Result wlaninfInitialize(void);
|
||||
void wlaninfExit(void);
|
||||
Service* wlaninfGetServiceSession(void);
|
||||
|
||||
/// Gets \ref WlanInfState.
|
||||
Result wlaninfGetState(WlanInfState* out);
|
||||
|
||||
/// Value goes from -30 (really good signal) to -90 (barely enough to stay connected)
|
||||
|
||||
370
nx/include/switch/sf/cmif.h
Normal file
370
nx/include/switch/sf/cmif.h
Normal file
@ -0,0 +1,370 @@
|
||||
/**
|
||||
* @file cmif.h
|
||||
* @brief Common Message Interface Framework protocol
|
||||
* @author fincs
|
||||
* @author SciresM
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "hipc.h"
|
||||
|
||||
#define CMIF_IN_HEADER_MAGIC 0x49434653 // "SFCI"
|
||||
#define CMIF_OUT_HEADER_MAGIC 0x4F434653 // "SFCO"
|
||||
|
||||
typedef enum CmifCommandType {
|
||||
CmifCommandType_Invalid = 0,
|
||||
CmifCommandType_LegacyRequest = 1,
|
||||
CmifCommandType_Close = 2,
|
||||
CmifCommandType_LegacyControl = 3,
|
||||
CmifCommandType_Request = 4,
|
||||
CmifCommandType_Control = 5,
|
||||
CmifCommandType_RequestWithContext = 6,
|
||||
CmifCommandType_ControlWithContext = 7,
|
||||
} CmifCommandType;
|
||||
|
||||
typedef enum CmifDomainRequestType {
|
||||
CmifDomainRequestType_Invalid = 0,
|
||||
CmifDomainRequestType_SendMessage = 1,
|
||||
CmifDomainRequestType_Close = 2,
|
||||
} CmifDomainRequestType;
|
||||
|
||||
typedef struct CmifInHeader {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 command_id;
|
||||
u32 token;
|
||||
} CmifInHeader;
|
||||
|
||||
typedef struct CmifOutHeader {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
Result result;
|
||||
u32 token;
|
||||
} CmifOutHeader;
|
||||
|
||||
typedef struct CmifDomainInHeader {
|
||||
u8 type;
|
||||
u8 num_in_objects;
|
||||
u16 data_size;
|
||||
u32 object_id;
|
||||
u32 padding;
|
||||
u32 token;
|
||||
} CmifDomainInHeader;
|
||||
|
||||
typedef struct CmifDomainOutHeader {
|
||||
u32 num_out_objects;
|
||||
u32 padding[3];
|
||||
} CmifDomainOutHeader;
|
||||
|
||||
typedef struct CmifRequestFormat {
|
||||
u32 object_id;
|
||||
u32 request_id;
|
||||
u32 context;
|
||||
u32 data_size;
|
||||
u32 server_pointer_size;
|
||||
u32 num_in_auto_buffers;
|
||||
u32 num_out_auto_buffers;
|
||||
u32 num_in_buffers;
|
||||
u32 num_out_buffers;
|
||||
u32 num_inout_buffers;
|
||||
u32 num_in_pointers;
|
||||
u32 num_out_pointers;
|
||||
u32 num_out_fixed_pointers;
|
||||
u32 num_objects;
|
||||
u32 num_handles;
|
||||
u32 send_pid;
|
||||
} CmifRequestFormat;
|
||||
|
||||
typedef struct CmifRequest {
|
||||
HipcRequest hipc;
|
||||
void* data;
|
||||
u16* out_pointer_sizes;
|
||||
u32* objects;
|
||||
u32 server_pointer_size;
|
||||
u32 cur_in_ptr_id;
|
||||
} CmifRequest;
|
||||
|
||||
typedef struct CmifResponse {
|
||||
void* data;
|
||||
u32* objects;
|
||||
Handle* copy_handles;
|
||||
Handle* move_handles;
|
||||
} CmifResponse;
|
||||
|
||||
NX_CONSTEXPR void* cmifGetAlignedDataStart(u32* data_words, void* base)
|
||||
{
|
||||
intptr_t data_start = ((u8*)data_words - (u8*)base + 15) &~ 15;
|
||||
return (u8*)base + data_start;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR CmifRequest cmifMakeRequest(void* base, CmifRequestFormat fmt)
|
||||
{
|
||||
// First of all, we need to figure out what size we need.
|
||||
u32 actual_size = 16;
|
||||
if (fmt.object_id)
|
||||
actual_size += sizeof(CmifDomainInHeader) + fmt.num_objects*sizeof(u32);
|
||||
actual_size += sizeof(CmifInHeader) + fmt.data_size;
|
||||
actual_size = (actual_size + 1) &~ 1; // hword-align
|
||||
u32 out_pointer_size_table_offset = actual_size;
|
||||
u32 out_pointer_size_table_size = fmt.num_out_auto_buffers + fmt.num_out_pointers;
|
||||
actual_size += sizeof(u16)*out_pointer_size_table_size;
|
||||
u32 num_data_words = (actual_size + 3) / 4;
|
||||
|
||||
CmifRequest req = {};
|
||||
req.hipc = hipcMakeRequestInline(base,
|
||||
.type = fmt.context ? CmifCommandType_RequestWithContext : CmifCommandType_Request,
|
||||
.num_send_statics = fmt.num_in_auto_buffers + fmt.num_in_pointers,
|
||||
.num_send_buffers = fmt.num_in_auto_buffers + fmt.num_in_buffers,
|
||||
.num_recv_buffers = fmt.num_out_auto_buffers + fmt.num_out_buffers,
|
||||
.num_exch_buffers = fmt.num_inout_buffers,
|
||||
.num_data_words = num_data_words,
|
||||
.num_recv_statics = out_pointer_size_table_size + fmt.num_out_fixed_pointers,
|
||||
.send_pid = fmt.send_pid,
|
||||
.num_copy_handles = fmt.num_handles,
|
||||
.num_move_handles = 0,
|
||||
);
|
||||
|
||||
CmifInHeader* hdr = NULL;
|
||||
void* start = cmifGetAlignedDataStart(req.hipc.data_words, base);
|
||||
if (fmt.object_id) {
|
||||
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)start;
|
||||
u32 payload_size = sizeof(CmifInHeader) + fmt.data_size;
|
||||
*domain_hdr = (CmifDomainInHeader){
|
||||
.type = CmifDomainRequestType_SendMessage,
|
||||
.num_in_objects = (u8)fmt.num_objects,
|
||||
.data_size = (u16)payload_size,
|
||||
.object_id = fmt.object_id,
|
||||
.padding = 0,
|
||||
.token = fmt.context,
|
||||
};
|
||||
hdr = (CmifInHeader*)(domain_hdr+1);
|
||||
req.objects = (u32*)((u8*)hdr + payload_size);
|
||||
} else
|
||||
hdr = (CmifInHeader*)start;
|
||||
|
||||
*hdr = (CmifInHeader){
|
||||
.magic = CMIF_IN_HEADER_MAGIC,
|
||||
.version = fmt.context ? 1U : 0U,
|
||||
.command_id = fmt.request_id,
|
||||
.token = fmt.object_id ? 0U : fmt.context,
|
||||
};
|
||||
|
||||
req.data = hdr+1;
|
||||
req.out_pointer_sizes = (u16*)(void*)((u8*)(void*)req.hipc.data_words + out_pointer_size_table_offset);
|
||||
req.server_pointer_size = fmt.server_pointer_size;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void* cmifMakeControlRequest(void* base, u32 request_id, u32 size)
|
||||
{
|
||||
u32 actual_size = 16 + sizeof(CmifInHeader) + size;
|
||||
HipcRequest hipc = hipcMakeRequestInline(base,
|
||||
.type = CmifCommandType_Control,
|
||||
.num_data_words = (actual_size + 3) / 4,
|
||||
);
|
||||
CmifInHeader* hdr = (CmifInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
|
||||
*hdr = (CmifInHeader){
|
||||
.magic = CMIF_IN_HEADER_MAGIC,
|
||||
.version = 0,
|
||||
.command_id = request_id,
|
||||
.token = 0,
|
||||
};
|
||||
return hdr+1;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifMakeCloseRequest(void* base, u32 object_id)
|
||||
{
|
||||
if (object_id) {
|
||||
HipcRequest hipc = hipcMakeRequestInline(base,
|
||||
.type = CmifCommandType_Request,
|
||||
.num_data_words = (16 + sizeof(CmifDomainInHeader)) / 4,
|
||||
);
|
||||
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
|
||||
*domain_hdr = (CmifDomainInHeader){
|
||||
.type = CmifDomainRequestType_Close,
|
||||
.object_id = object_id,
|
||||
};
|
||||
} else {
|
||||
hipcMakeRequestInline(base,
|
||||
.type = CmifCommandType_Close,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestInBuffer(CmifRequest* req, const void* buffer, size_t size, HipcBufferMode mode)
|
||||
{
|
||||
*req->hipc.send_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
|
||||
{
|
||||
*req->hipc.recv_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestInOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
|
||||
{
|
||||
*req->hipc.exch_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestInPointer(CmifRequest* req, const void* buffer, size_t size)
|
||||
{
|
||||
*req->hipc.send_statics++ = hipcMakeSendStatic(buffer, size, req->cur_in_ptr_id++);
|
||||
req->server_pointer_size -= size;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestOutFixedPointer(CmifRequest* req, void* buffer, size_t size)
|
||||
{
|
||||
*req->hipc.recv_list++ = hipcMakeRecvStatic(buffer, size);
|
||||
req->server_pointer_size -= size;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestOutPointer(CmifRequest* req, void* buffer, size_t size)
|
||||
{
|
||||
cmifRequestOutFixedPointer(req, buffer, size);
|
||||
*req->out_pointer_sizes++ = size;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestInAutoBuffer(CmifRequest* req, const void* buffer, size_t size)
|
||||
{
|
||||
if (req->server_pointer_size && size <= req->server_pointer_size) {
|
||||
cmifRequestInPointer(req, buffer, size);
|
||||
cmifRequestInBuffer(req, NULL, 0, HipcBufferMode_Normal);
|
||||
} else {
|
||||
cmifRequestInPointer(req, NULL, 0);
|
||||
cmifRequestInBuffer(req, buffer, size, HipcBufferMode_Normal);
|
||||
}
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestOutAutoBuffer(CmifRequest* req, void* buffer, size_t size)
|
||||
{
|
||||
if (req->server_pointer_size && size <= req->server_pointer_size) {
|
||||
cmifRequestOutPointer(req, buffer, size);
|
||||
cmifRequestOutBuffer(req, NULL, 0, HipcBufferMode_Normal);
|
||||
} else {
|
||||
cmifRequestOutPointer(req, NULL, 0);
|
||||
cmifRequestOutBuffer(req, buffer, size, HipcBufferMode_Normal);
|
||||
}
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestObject(CmifRequest* req, u32 object_id)
|
||||
{
|
||||
*req->objects++ = object_id;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void cmifRequestHandle(CmifRequest* req, Handle handle)
|
||||
{
|
||||
*req->hipc.copy_handles++ = handle;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR Result cmifParseResponse(CmifResponse* res, void* base, bool is_domain, u32 size)
|
||||
{
|
||||
HipcResponse hipc = hipcParseResponse(base);
|
||||
void* start = cmifGetAlignedDataStart(hipc.data_words, base);
|
||||
|
||||
CmifOutHeader* hdr = NULL;
|
||||
u32* objects = NULL;
|
||||
if (is_domain) {
|
||||
CmifDomainOutHeader* domain_hdr = (CmifDomainOutHeader*)start;
|
||||
hdr = (CmifOutHeader*)(domain_hdr+1);
|
||||
objects = (u32*)((u8*)hdr + sizeof(CmifOutHeader) + size);
|
||||
}
|
||||
else
|
||||
hdr = (CmifOutHeader*)start;
|
||||
|
||||
if (hdr->magic != CMIF_OUT_HEADER_MAGIC)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_InvalidCmifOutHeader);
|
||||
if (R_FAILED(hdr->result))
|
||||
return hdr->result;
|
||||
|
||||
*res = (CmifResponse){
|
||||
.data = hdr+1,
|
||||
.objects = objects,
|
||||
.copy_handles = hipc.copy_handles,
|
||||
.move_handles = hipc.move_handles,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR u32 cmifResponseGetObject(CmifResponse* res)
|
||||
{
|
||||
return *res->objects++;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR Handle cmifResponseGetCopyHandle(CmifResponse* res)
|
||||
{
|
||||
return *res->copy_handles++;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR Handle cmifResponseGetMoveHandle(CmifResponse* res)
|
||||
{
|
||||
return *res->move_handles++;
|
||||
}
|
||||
|
||||
NX_INLINE Result cmifConvertCurrentObjectToDomain(Handle h, u32* out_object_id)
|
||||
{
|
||||
cmifMakeControlRequest(armGetTls(), 0, 0);
|
||||
Result rc = svcSendSyncRequest(h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
CmifResponse resp = {};
|
||||
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u32));
|
||||
if (R_SUCCEEDED(rc) && out_object_id)
|
||||
*out_object_id = *(u32*)resp.data;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE Result cmifCopyFromCurrentDomain(Handle h, u32 object_id, Handle* out_h)
|
||||
{
|
||||
void* raw = cmifMakeControlRequest(armGetTls(), 1, sizeof(u32));
|
||||
*(u32*)raw = object_id;
|
||||
Result rc = svcSendSyncRequest(h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
CmifResponse resp = {};
|
||||
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
|
||||
if (R_SUCCEEDED(rc) && out_h)
|
||||
*out_h = resp.move_handles[0];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE Result cmifCloneCurrentObject(Handle h, Handle* out_h)
|
||||
{
|
||||
cmifMakeControlRequest(armGetTls(), 2, 0);
|
||||
Result rc = svcSendSyncRequest(h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
CmifResponse resp = {};
|
||||
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
|
||||
if (R_SUCCEEDED(rc) && out_h)
|
||||
*out_h = resp.move_handles[0];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE Result cmifQueryPointerBufferSize(Handle h, u16* out_size)
|
||||
{
|
||||
cmifMakeControlRequest(armGetTls(), 3, 0);
|
||||
Result rc = svcSendSyncRequest(h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
CmifResponse resp = {};
|
||||
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u16));
|
||||
if (R_SUCCEEDED(rc) && out_size)
|
||||
*out_size = *(u16*)resp.data;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE Result cmifCloneCurrentObjectEx(Handle h, u32 tag, Handle* out_h)
|
||||
{
|
||||
void* raw = cmifMakeControlRequest(armGetTls(), 4, sizeof(u32));
|
||||
*(u32*)raw = tag;
|
||||
Result rc = svcSendSyncRequest(h);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
CmifResponse resp = {};
|
||||
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
|
||||
if (R_SUCCEEDED(rc) && out_h)
|
||||
*out_h = resp.move_handles[0];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
363
nx/include/switch/sf/hipc.h
Normal file
363
nx/include/switch/sf/hipc.h
Normal file
@ -0,0 +1,363 @@
|
||||
/**
|
||||
* @file hipc.h
|
||||
* @brief Horizon Inter-Process Communication protocol
|
||||
* @author fincs
|
||||
* @author SciresM
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../result.h"
|
||||
#include "../arm/tls.h"
|
||||
#include "../kernel/svc.h"
|
||||
|
||||
#define HIPC_AUTO_RECV_STATIC UINT8_MAX
|
||||
#define HIPC_RESPONSE_NO_PID UINT32_MAX
|
||||
|
||||
typedef struct HipcMetadata {
|
||||
u32 type;
|
||||
u32 num_send_statics;
|
||||
u32 num_send_buffers;
|
||||
u32 num_recv_buffers;
|
||||
u32 num_exch_buffers;
|
||||
u32 num_data_words;
|
||||
u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC
|
||||
u32 send_pid;
|
||||
u32 num_copy_handles;
|
||||
u32 num_move_handles;
|
||||
} HipcMetadata;
|
||||
|
||||
typedef struct HipcHeader {
|
||||
u32 type : 16;
|
||||
u32 num_send_statics : 4;
|
||||
u32 num_send_buffers : 4;
|
||||
u32 num_recv_buffers : 4;
|
||||
u32 num_exch_buffers : 4;
|
||||
u32 num_data_words : 10;
|
||||
u32 recv_static_mode : 4;
|
||||
u32 padding : 6;
|
||||
u32 recv_list_offset : 11; // Unused.
|
||||
u32 has_special_header : 1;
|
||||
} HipcHeader;
|
||||
|
||||
typedef struct HipcSpecialHeader {
|
||||
u32 send_pid : 1;
|
||||
u32 num_copy_handles : 4;
|
||||
u32 num_move_handles : 4;
|
||||
u32 padding : 23;
|
||||
} HipcSpecialHeader;
|
||||
|
||||
typedef struct HipcStaticDescriptor {
|
||||
u32 index : 6;
|
||||
u32 address_high : 6;
|
||||
u32 address_mid : 4;
|
||||
u32 size : 16;
|
||||
u32 address_low;
|
||||
} HipcStaticDescriptor;
|
||||
|
||||
typedef struct HipcBufferDescriptor {
|
||||
u32 size_low;
|
||||
u32 address_low;
|
||||
u32 mode : 2;
|
||||
u32 address_high : 22;
|
||||
u32 size_high : 4;
|
||||
u32 address_mid : 4;
|
||||
} HipcBufferDescriptor;
|
||||
|
||||
typedef struct HipcRecvListEntry {
|
||||
u32 address_low;
|
||||
u32 address_high : 16;
|
||||
u32 size : 16;
|
||||
} HipcRecvListEntry;
|
||||
|
||||
typedef struct HipcRequest {
|
||||
HipcStaticDescriptor* send_statics;
|
||||
HipcBufferDescriptor* send_buffers;
|
||||
HipcBufferDescriptor* recv_buffers;
|
||||
HipcBufferDescriptor* exch_buffers;
|
||||
u32* data_words;
|
||||
HipcRecvListEntry* recv_list;
|
||||
Handle* copy_handles;
|
||||
Handle* move_handles;
|
||||
} HipcRequest;
|
||||
|
||||
typedef struct HipcParsedRequest {
|
||||
HipcMetadata meta;
|
||||
HipcRequest data;
|
||||
u64 pid;
|
||||
} HipcParsedRequest;
|
||||
|
||||
typedef struct HipcResponse {
|
||||
u64 pid;
|
||||
u32 num_statics;
|
||||
u32 num_data_words;
|
||||
u32 num_copy_handles;
|
||||
u32 num_move_handles;
|
||||
HipcStaticDescriptor* statics;
|
||||
u32* data_words;
|
||||
Handle* copy_handles;
|
||||
Handle* move_handles;
|
||||
} HipcResponse;
|
||||
|
||||
typedef enum HipcBufferMode {
|
||||
HipcBufferMode_Normal = 0,
|
||||
HipcBufferMode_NonSecure = 1,
|
||||
HipcBufferMode_Invalid = 2,
|
||||
HipcBufferMode_NonDevice = 3,
|
||||
} HipcBufferMode;
|
||||
|
||||
NX_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index)
|
||||
{
|
||||
return (HipcStaticDescriptor){
|
||||
.index = index,
|
||||
.address_high = (u32)((uintptr_t)buffer >> 36),
|
||||
.address_mid = (u32)((uintptr_t)buffer >> 32),
|
||||
.size = (u32)size,
|
||||
.address_low = (u32)(uintptr_t)buffer,
|
||||
};
|
||||
}
|
||||
|
||||
NX_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode)
|
||||
{
|
||||
return (HipcBufferDescriptor){
|
||||
.size_low = (u32)size,
|
||||
.address_low = (u32)(uintptr_t)buffer,
|
||||
.mode = mode,
|
||||
.address_high = (u32)((uintptr_t)buffer >> 36),
|
||||
.size_high = (u32)(size >> 32),
|
||||
.address_mid = (u32)((uintptr_t)buffer >> 32),
|
||||
};
|
||||
}
|
||||
|
||||
NX_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size)
|
||||
{
|
||||
return (HipcRecvListEntry){
|
||||
.address_low = (u32)((uintptr_t)buffer),
|
||||
.address_high = (u32)((uintptr_t)buffer >> 32),
|
||||
.size = (u32)size,
|
||||
};
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc)
|
||||
{
|
||||
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
|
||||
}
|
||||
|
||||
NX_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc)
|
||||
{
|
||||
return desc->size;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc)
|
||||
{
|
||||
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
|
||||
}
|
||||
|
||||
NX_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc)
|
||||
{
|
||||
return desc->size_low | ((size_t)desc->size_high << 32);
|
||||
}
|
||||
|
||||
NX_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base)
|
||||
{
|
||||
// Copy handles
|
||||
Handle* copy_handles = NULL;
|
||||
if (meta.num_copy_handles) {
|
||||
copy_handles = (Handle*)base;
|
||||
base = copy_handles + meta.num_copy_handles;
|
||||
}
|
||||
|
||||
// Move handles
|
||||
Handle* move_handles = NULL;
|
||||
if (meta.num_move_handles) {
|
||||
move_handles = (Handle*)base;
|
||||
base = move_handles + meta.num_move_handles;
|
||||
}
|
||||
|
||||
// Send statics
|
||||
HipcStaticDescriptor* send_statics = NULL;
|
||||
if (meta.num_send_statics) {
|
||||
send_statics = (HipcStaticDescriptor*)base;
|
||||
base = send_statics + meta.num_send_statics;
|
||||
}
|
||||
|
||||
// Send buffers
|
||||
HipcBufferDescriptor* send_buffers = NULL;
|
||||
if (meta.num_send_buffers) {
|
||||
send_buffers = (HipcBufferDescriptor*)base;
|
||||
base = send_buffers + meta.num_send_buffers;
|
||||
}
|
||||
|
||||
// Recv buffers
|
||||
HipcBufferDescriptor* recv_buffers = NULL;
|
||||
if (meta.num_recv_buffers) {
|
||||
recv_buffers = (HipcBufferDescriptor*)base;
|
||||
base = recv_buffers + meta.num_recv_buffers;
|
||||
}
|
||||
|
||||
// Exch buffers
|
||||
HipcBufferDescriptor* exch_buffers = NULL;
|
||||
if (meta.num_exch_buffers) {
|
||||
exch_buffers = (HipcBufferDescriptor*)base;
|
||||
base = exch_buffers + meta.num_exch_buffers;
|
||||
}
|
||||
|
||||
// Data words
|
||||
u32* data_words = NULL;
|
||||
if (meta.num_data_words) {
|
||||
data_words = (u32*)base;
|
||||
base = data_words + meta.num_data_words;
|
||||
}
|
||||
|
||||
// Recv list
|
||||
HipcRecvListEntry* recv_list = NULL;
|
||||
if (meta.num_recv_statics)
|
||||
recv_list = (HipcRecvListEntry*)base;
|
||||
|
||||
return (HipcRequest){
|
||||
.send_statics = send_statics,
|
||||
.send_buffers = send_buffers,
|
||||
.recv_buffers = recv_buffers,
|
||||
.exch_buffers = exch_buffers,
|
||||
.data_words = data_words,
|
||||
.recv_list = recv_list,
|
||||
.copy_handles = copy_handles,
|
||||
.move_handles = move_handles,
|
||||
};
|
||||
}
|
||||
|
||||
NX_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta)
|
||||
{
|
||||
// Write message header
|
||||
bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles;
|
||||
HipcHeader* hdr = (HipcHeader*)base;
|
||||
base = hdr+1;
|
||||
*hdr = (HipcHeader){
|
||||
.type = meta.type,
|
||||
.num_send_statics = meta.num_send_statics,
|
||||
.num_send_buffers = meta.num_send_buffers,
|
||||
.num_recv_buffers = meta.num_recv_buffers,
|
||||
.num_exch_buffers = meta.num_exch_buffers,
|
||||
.num_data_words = meta.num_data_words,
|
||||
.recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u,
|
||||
.padding = 0,
|
||||
.recv_list_offset = 0,
|
||||
.has_special_header = has_special_header,
|
||||
};
|
||||
|
||||
// Write special header
|
||||
if (has_special_header) {
|
||||
HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base;
|
||||
base = sphdr+1;
|
||||
*sphdr = (HipcSpecialHeader){
|
||||
.send_pid = meta.send_pid,
|
||||
.num_copy_handles = meta.num_copy_handles,
|
||||
.num_move_handles = meta.num_move_handles,
|
||||
};
|
||||
if (meta.send_pid)
|
||||
base = (u8*)base + sizeof(u64);
|
||||
}
|
||||
|
||||
// Calculate layout
|
||||
return hipcCalcRequestLayout(meta, base);
|
||||
}
|
||||
|
||||
#define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ })
|
||||
|
||||
NX_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base)
|
||||
{
|
||||
// Parse message header
|
||||
HipcHeader hdr = {};
|
||||
__builtin_memcpy(&hdr, base, sizeof(hdr));
|
||||
base = (u8*)base + sizeof(hdr);
|
||||
u32 num_recv_statics = 0;
|
||||
u64 pid = 0;
|
||||
|
||||
// Parse recv static mode
|
||||
if (hdr.recv_static_mode) {
|
||||
if (hdr.recv_static_mode == 2u)
|
||||
num_recv_statics = HIPC_AUTO_RECV_STATIC;
|
||||
else if (hdr.recv_static_mode > 2u)
|
||||
num_recv_statics = hdr.recv_static_mode - 2u;
|
||||
}
|
||||
|
||||
// Parse special header
|
||||
HipcSpecialHeader sphdr = {};
|
||||
if (hdr.has_special_header) {
|
||||
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
|
||||
base = (u8*)base + sizeof(sphdr);
|
||||
|
||||
// Read PID descriptor
|
||||
if (sphdr.send_pid) {
|
||||
pid = *(u64*)base;
|
||||
base = (u8*)base + sizeof(u64);
|
||||
}
|
||||
}
|
||||
|
||||
const HipcMetadata meta = {
|
||||
.type = hdr.type,
|
||||
.num_send_statics = hdr.num_send_statics,
|
||||
.num_send_buffers = hdr.num_send_buffers,
|
||||
.num_recv_buffers = hdr.num_recv_buffers,
|
||||
.num_exch_buffers = hdr.num_exch_buffers,
|
||||
.num_data_words = hdr.num_data_words,
|
||||
.num_recv_statics = num_recv_statics,
|
||||
.send_pid = sphdr.send_pid,
|
||||
.num_copy_handles = sphdr.num_copy_handles,
|
||||
.num_move_handles = sphdr.num_move_handles,
|
||||
};
|
||||
|
||||
return (HipcParsedRequest){
|
||||
.meta = meta,
|
||||
.data = hipcCalcRequestLayout(meta, base),
|
||||
.pid = pid,
|
||||
};
|
||||
}
|
||||
|
||||
NX_CONSTEXPR HipcResponse hipcParseResponse(void* base)
|
||||
{
|
||||
// Parse header
|
||||
HipcHeader hdr = {};
|
||||
__builtin_memcpy(&hdr, base, sizeof(hdr));
|
||||
base = (u8*)base + sizeof(hdr);
|
||||
|
||||
// Initialize response
|
||||
HipcResponse response = {};
|
||||
response.num_statics = hdr.num_send_statics;
|
||||
response.num_data_words = hdr.num_data_words;
|
||||
response.pid = HIPC_RESPONSE_NO_PID;
|
||||
|
||||
// Parse special header
|
||||
if (hdr.has_special_header)
|
||||
{
|
||||
HipcSpecialHeader sphdr = {};
|
||||
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
|
||||
base = (u8*)base + sizeof(sphdr);
|
||||
|
||||
// Update response
|
||||
response.num_copy_handles = sphdr.num_copy_handles;
|
||||
response.num_move_handles = sphdr.num_move_handles;
|
||||
|
||||
// Parse PID descriptor
|
||||
if (sphdr.send_pid) {
|
||||
response.pid = *(u64*)base;
|
||||
base = (u8*)base + sizeof(u64);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy handles
|
||||
response.copy_handles = (Handle*)base;
|
||||
base = response.copy_handles + response.num_copy_handles;
|
||||
|
||||
// Move handles
|
||||
response.move_handles = (Handle*)base;
|
||||
base = response.move_handles + response.num_move_handles;
|
||||
|
||||
// Send statics
|
||||
response.statics = (HipcStaticDescriptor*)base;
|
||||
base = response.statics + response.num_statics;
|
||||
|
||||
// Data words
|
||||
response.data_words = (u32*)base;
|
||||
|
||||
return response;
|
||||
}
|
||||
459
nx/include/switch/sf/service.h
Normal file
459
nx/include/switch/sf/service.h
Normal file
@ -0,0 +1,459 @@
|
||||
/**
|
||||
* @file service.h
|
||||
* @brief Service wrapper object
|
||||
* @author fincs
|
||||
* @author SciresM
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "hipc.h"
|
||||
#include "cmif.h"
|
||||
|
||||
/// Service object structure
|
||||
typedef struct Service {
|
||||
Handle session;
|
||||
u32 own_handle;
|
||||
u32 object_id;
|
||||
u16 pointer_buffer_size;
|
||||
} Service;
|
||||
|
||||
enum {
|
||||
SfBufferAttr_In = BIT(0),
|
||||
SfBufferAttr_Out = BIT(1),
|
||||
SfBufferAttr_HipcMapAlias = BIT(2),
|
||||
SfBufferAttr_HipcPointer = BIT(3),
|
||||
SfBufferAttr_FixedSize = BIT(4),
|
||||
SfBufferAttr_HipcAutoSelect = BIT(5),
|
||||
SfBufferAttr_HipcMapTransferAllowsNonSecure = BIT(6),
|
||||
SfBufferAttr_HipcMapTransferAllowsNonDevice = BIT(7),
|
||||
};
|
||||
|
||||
typedef struct SfBufferAttrs {
|
||||
u32 attr0;
|
||||
u32 attr1;
|
||||
u32 attr2;
|
||||
u32 attr3;
|
||||
u32 attr4;
|
||||
u32 attr5;
|
||||
u32 attr6;
|
||||
u32 attr7;
|
||||
} SfBufferAttrs;
|
||||
|
||||
typedef struct SfBuffer {
|
||||
const void* ptr;
|
||||
size_t size;
|
||||
} SfBuffer;
|
||||
|
||||
typedef enum SfOutHandleAttr {
|
||||
SfOutHandleAttr_None = 0,
|
||||
SfOutHandleAttr_HipcCopy = 1,
|
||||
SfOutHandleAttr_HipcMove = 2,
|
||||
} SfOutHandleAttr;
|
||||
|
||||
typedef struct SfOutHandleAttrs {
|
||||
SfOutHandleAttr attr0;
|
||||
SfOutHandleAttr attr1;
|
||||
SfOutHandleAttr attr2;
|
||||
SfOutHandleAttr attr3;
|
||||
SfOutHandleAttr attr4;
|
||||
SfOutHandleAttr attr5;
|
||||
SfOutHandleAttr attr6;
|
||||
SfOutHandleAttr attr7;
|
||||
} SfOutHandleAttrs;
|
||||
|
||||
typedef struct SfDispatchParams {
|
||||
Handle target_session;
|
||||
u32 context;
|
||||
|
||||
SfBufferAttrs buffer_attrs;
|
||||
SfBuffer buffers[8];
|
||||
|
||||
bool in_send_pid;
|
||||
|
||||
u32 in_num_objects;
|
||||
const Service* in_objects[8];
|
||||
|
||||
u32 in_num_handles;
|
||||
Handle in_handles[8];
|
||||
|
||||
u32 out_num_objects;
|
||||
Service* out_objects;
|
||||
|
||||
SfOutHandleAttrs out_handle_attrs;
|
||||
Handle* out_handles;
|
||||
} SfDispatchParams;
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service has been initialized.
|
||||
* @param[in] s Service object.
|
||||
* @return true if initialized.
|
||||
*/
|
||||
NX_CONSTEXPR bool serviceIsActive(Service* s) {
|
||||
return s->session != INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is overriden in the homebrew environment.
|
||||
* @param[in] s Service object.
|
||||
* @return true if overriden.
|
||||
*/
|
||||
NX_CONSTEXPR bool serviceIsOverride(Service* s) {
|
||||
return serviceIsActive(s) && !s->own_handle && !s->object_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is a domain.
|
||||
* @param[in] s Service object.
|
||||
* @return true if a domain.
|
||||
*/
|
||||
NX_CONSTEXPR bool serviceIsDomain(Service* s) {
|
||||
return serviceIsActive(s) && s->own_handle && s->object_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether a service is a domain subservice.
|
||||
* @param[in] s Service object.
|
||||
* @return true if a domain subservice.
|
||||
*/
|
||||
NX_CONSTEXPR bool serviceIsDomainSubservice(Service* s) {
|
||||
return serviceIsActive(s) && !s->own_handle && s->object_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For a domain/domain subservice, return the associated object ID.
|
||||
* @param[in] s Service object, necessarily a domain or domain subservice.
|
||||
* @return The object ID.
|
||||
*/
|
||||
NX_CONSTEXPR u32 serviceGetObjectId(Service* s) {
|
||||
return s->object_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a service object from an IPC session handle.
|
||||
* @param[out] s Service object.
|
||||
* @param[in] h IPC session handle.
|
||||
*/
|
||||
NX_INLINE void serviceCreate(Service* s, Handle h)
|
||||
{
|
||||
s->session = h;
|
||||
s->own_handle = 1;
|
||||
s->object_id = 0;
|
||||
s->pointer_buffer_size = 0;
|
||||
cmifQueryPointerBufferSize(h, &s->pointer_buffer_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a domain subservice object from a parent service.
|
||||
* @param[out] s Service object.
|
||||
* @param[in] parent Parent service, necessarily a domain or domain subservice.
|
||||
* @param[in] object_id Object ID for this subservice.
|
||||
*/
|
||||
NX_CONSTEXPR void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id)
|
||||
{
|
||||
s->session = parent->session;
|
||||
s->own_handle = 0;
|
||||
s->object_id = object_id;
|
||||
s->pointer_buffer_size = parent->pointer_buffer_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Hints the compiler that a service will always contain a domain object.
|
||||
* @param[in] _s Service object.
|
||||
*/
|
||||
#define serviceAssumeDomain(_s) do { \
|
||||
if (!(_s)->object_id) \
|
||||
__builtin_unreachable(); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief Closes a service.
|
||||
* @param[in] s Service object.
|
||||
*/
|
||||
NX_INLINE void serviceClose(Service* s)
|
||||
{
|
||||
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
|
||||
if (s->object_id)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
|
||||
if (s->own_handle || s->object_id) {
|
||||
cmifMakeCloseRequest(armGetTls(), s->own_handle ? 0 : s->object_id);
|
||||
svcSendSyncRequest(s->session);
|
||||
if (s->own_handle)
|
||||
svcCloseHandle(s->session);
|
||||
}
|
||||
*s = (Service){};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clones a service.
|
||||
* @param[in] s Service object.
|
||||
* @param[out] out_s Output service object.
|
||||
*/
|
||||
NX_INLINE Result serviceClone(Service* s, Service* out_s)
|
||||
{
|
||||
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
|
||||
if (s->object_id)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
|
||||
out_s->session = 0;
|
||||
out_s->own_handle = 1;
|
||||
out_s->object_id = s->object_id;
|
||||
out_s->pointer_buffer_size = s->pointer_buffer_size;
|
||||
return cmifCloneCurrentObject(s->session, &out_s->session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clones a service with a session manager tag.
|
||||
* @param[in] s Service object.
|
||||
* @param[in] tag Session manager tag (unused in current official server code)
|
||||
* @param[out] out_s Output service object.
|
||||
*/
|
||||
NX_INLINE Result serviceCloneEx(Service* s, u32 tag, Service* out_s)
|
||||
{
|
||||
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
|
||||
if (s->object_id)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
|
||||
out_s->session = 0;
|
||||
out_s->own_handle = 1;
|
||||
out_s->object_id = s->object_id;
|
||||
out_s->pointer_buffer_size = s->pointer_buffer_size;
|
||||
return cmifCloneCurrentObjectEx(s->session, tag, &out_s->session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a regular service to a domain.
|
||||
* @param[in] s Service object.
|
||||
* @return Result code.
|
||||
*/
|
||||
NX_INLINE Result serviceConvertToDomain(Service* s)
|
||||
{
|
||||
if (!s->own_handle) {
|
||||
// For overridden services, create a clone first.
|
||||
Result rc = cmifCloneCurrentObjectEx(s->session, 0, &s->session);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
s->own_handle = 1;
|
||||
}
|
||||
|
||||
return cmifConvertCurrentObjectToDomain(s->session, &s->object_id);
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void _serviceRequestFormatProcessBuffer(CmifRequestFormat* fmt, u32 attr)
|
||||
{
|
||||
if (!attr) return;
|
||||
const bool is_in = (attr & SfBufferAttr_In) != 0;
|
||||
const bool is_out = (attr & SfBufferAttr_Out) != 0;
|
||||
|
||||
if (attr & SfBufferAttr_HipcAutoSelect) {
|
||||
if (is_in)
|
||||
fmt->num_in_auto_buffers ++;
|
||||
if (is_out)
|
||||
fmt->num_out_auto_buffers ++;
|
||||
} else if (attr & SfBufferAttr_HipcPointer) {
|
||||
if (is_in)
|
||||
fmt->num_in_pointers ++;
|
||||
if (is_out) {
|
||||
if (attr & SfBufferAttr_FixedSize)
|
||||
fmt->num_out_fixed_pointers ++;
|
||||
else
|
||||
fmt->num_out_pointers ++;
|
||||
}
|
||||
} else if (attr & SfBufferAttr_HipcMapAlias) {
|
||||
if (is_in && is_out)
|
||||
fmt->num_inout_buffers ++;
|
||||
else if (is_in)
|
||||
fmt->num_in_buffers ++;
|
||||
else if (is_out)
|
||||
fmt->num_out_buffers ++;
|
||||
}
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void _serviceRequestProcessBuffer(CmifRequest* req, const SfBuffer* buf, u32 attr)
|
||||
{
|
||||
if (!attr) return;
|
||||
const bool is_in = (attr & SfBufferAttr_In);
|
||||
const bool is_out = (attr & SfBufferAttr_Out);
|
||||
|
||||
if (attr & SfBufferAttr_HipcAutoSelect) {
|
||||
if (is_in)
|
||||
cmifRequestInAutoBuffer(req, buf->ptr, buf->size);
|
||||
if (is_out)
|
||||
cmifRequestOutAutoBuffer(req, (void*)buf->ptr, buf->size);
|
||||
} else if (attr & SfBufferAttr_HipcPointer) {
|
||||
if (is_in)
|
||||
cmifRequestInPointer(req, buf->ptr, buf->size);
|
||||
if (is_out) {
|
||||
if (attr & SfBufferAttr_FixedSize)
|
||||
cmifRequestOutFixedPointer(req, (void*)buf->ptr, buf->size);
|
||||
else
|
||||
cmifRequestOutPointer(req, (void*)buf->ptr, buf->size);
|
||||
}
|
||||
} else if (attr & SfBufferAttr_HipcMapAlias) {
|
||||
HipcBufferMode mode = HipcBufferMode_Normal;
|
||||
if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
|
||||
mode = HipcBufferMode_NonSecure;
|
||||
if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
|
||||
mode = HipcBufferMode_NonDevice;
|
||||
|
||||
if (is_in && is_out)
|
||||
cmifRequestInOutBuffer(req, (void*)buf->ptr, buf->size, mode);
|
||||
else if (is_in)
|
||||
cmifRequestInBuffer(req, buf->ptr, buf->size, mode);
|
||||
else if (is_out)
|
||||
cmifRequestOutBuffer(req, (void*)buf->ptr, buf->size, mode);
|
||||
}
|
||||
}
|
||||
|
||||
NX_INLINE void* serviceMakeRequest(
|
||||
Service* s, u32 request_id, u32 context, u32 data_size, bool send_pid,
|
||||
const SfBufferAttrs buffer_attrs, const SfBuffer* buffers,
|
||||
u32 num_objects, const Service* const* objects,
|
||||
u32 num_handles, const Handle* handles
|
||||
) {
|
||||
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
|
||||
if (s->object_id)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
|
||||
CmifRequestFormat fmt = {};
|
||||
fmt.object_id = s->object_id;
|
||||
fmt.request_id = request_id;
|
||||
fmt.context = context;
|
||||
fmt.data_size = data_size;
|
||||
fmt.server_pointer_size = s->pointer_buffer_size;
|
||||
fmt.num_objects = num_objects;
|
||||
fmt.num_handles = num_handles;
|
||||
fmt.send_pid = send_pid;
|
||||
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr0);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr1);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr2);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr3);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr4);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr5);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr6);
|
||||
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr7);
|
||||
|
||||
CmifRequest req = cmifMakeRequest(armGetTls(), fmt);
|
||||
|
||||
if (s->object_id) // TODO: Check behavior of input objects in non-domain sessions
|
||||
for (u32 i = 0; i < num_objects; i ++)
|
||||
cmifRequestObject(&req, objects[i]->object_id);
|
||||
|
||||
for (u32 i = 0; i < num_handles; i ++)
|
||||
cmifRequestHandle(&req, handles[i]);
|
||||
|
||||
_serviceRequestProcessBuffer(&req, &buffers[0], buffer_attrs.attr0);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[1], buffer_attrs.attr1);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[2], buffer_attrs.attr2);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[3], buffer_attrs.attr3);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[4], buffer_attrs.attr4);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[5], buffer_attrs.attr5);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[6], buffer_attrs.attr6);
|
||||
_serviceRequestProcessBuffer(&req, &buffers[7], buffer_attrs.attr7);
|
||||
|
||||
return req.data;
|
||||
}
|
||||
|
||||
NX_CONSTEXPR void _serviceResponseGetHandle(CmifResponse* res, SfOutHandleAttr type, Handle* out)
|
||||
{
|
||||
switch (type) {
|
||||
default:
|
||||
case SfOutHandleAttr_None:
|
||||
break;
|
||||
case SfOutHandleAttr_HipcCopy:
|
||||
*out = cmifResponseGetCopyHandle(res);
|
||||
break;
|
||||
case SfOutHandleAttr_HipcMove:
|
||||
*out = cmifResponseGetMoveHandle(res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NX_INLINE Result serviceParseResponse(
|
||||
Service* s, u32 out_size, void** out_data,
|
||||
u32 num_out_objects, Service* out_objects,
|
||||
const SfOutHandleAttrs out_handle_attrs, Handle* out_handles
|
||||
) {
|
||||
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
|
||||
if (s->object_id)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
|
||||
CmifResponse res = {};
|
||||
bool is_domain = s->object_id != 0;
|
||||
Result rc = cmifParseResponse(&res, armGetTls(), is_domain, out_size);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
if (out_size)
|
||||
*out_data = res.data;
|
||||
|
||||
for (u32 i = 0; i < num_out_objects; i ++) {
|
||||
if (is_domain)
|
||||
serviceCreateDomainSubservice(&out_objects[i], s, cmifResponseGetObject(&res));
|
||||
else // Output objects are marshalled as move handles at the beginning of the list.
|
||||
serviceCreate(&out_objects[i], cmifResponseGetMoveHandle(&res));
|
||||
}
|
||||
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr0, &out_handles[0]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr1, &out_handles[1]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr2, &out_handles[2]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr3, &out_handles[3]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr4, &out_handles[4]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr5, &out_handles[5]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr6, &out_handles[6]);
|
||||
_serviceResponseGetHandle(&res, out_handle_attrs.attr7, &out_handles[7]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NX_INLINE Result serviceDispatchImpl(
|
||||
Service* s, u32 request_id,
|
||||
const void* in_data, u32 in_data_size,
|
||||
void* out_data, u32 out_data_size,
|
||||
SfDispatchParams disp
|
||||
)
|
||||
{
|
||||
// Make a copy of the service struct, so that the compiler can assume that it won't be modified by function calls.
|
||||
Service srv = *s;
|
||||
|
||||
void* in = serviceMakeRequest(&srv, request_id, disp.context,
|
||||
in_data_size, disp.in_send_pid,
|
||||
disp.buffer_attrs, disp.buffers,
|
||||
disp.in_num_objects, disp.in_objects,
|
||||
disp.in_num_handles, disp.in_handles);
|
||||
|
||||
if (in_data_size)
|
||||
__builtin_memcpy(in, in_data, in_data_size);
|
||||
|
||||
Result rc = svcSendSyncRequest(disp.target_session == INVALID_HANDLE ? s->session : disp.target_session);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
void* out = NULL;
|
||||
rc = serviceParseResponse(&srv,
|
||||
out_data_size, &out,
|
||||
disp.out_num_objects, disp.out_objects,
|
||||
disp.out_handle_attrs, disp.out_handles);
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_data && out_data_size)
|
||||
__builtin_memcpy(out_data, out, out_data_size);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define serviceDispatch(_s,_rid,...) \
|
||||
serviceDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceDispatchIn(_s,_rid,_in,...) \
|
||||
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceDispatchOut(_s,_rid,_out,...) \
|
||||
serviceDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceDispatchInOut(_s,_rid,_in,_out,...) \
|
||||
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
|
||||
@ -77,5 +77,15 @@ typedef void (*VoidFn)(void); ///< Function without arguments nor return v
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Flags a function as (always) inline.
|
||||
#define NX_INLINE __attribute__((always_inline)) static inline
|
||||
|
||||
/// Flags a function as constexpr in C++14 and above; or as (always) inline otherwise.
|
||||
#if __cplusplus >= 201402L
|
||||
#define NX_CONSTEXPR NX_INLINE constexpr
|
||||
#else
|
||||
#define NX_CONSTEXPR NX_INLINE
|
||||
#endif
|
||||
|
||||
/// Invalid handle.
|
||||
#define INVALID_HANDLE ((Handle) 0)
|
||||
|
||||
31
nx/source/applets/album_la.c
Normal file
31
nx/source/applets/album_la.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "services/applet.h"
|
||||
#include "applets/libapplet.h"
|
||||
#include "applets/album_la.h"
|
||||
|
||||
static Result _albumLaShow(u8 arg, bool playStartupSound) {
|
||||
Result rc=0;
|
||||
LibAppletArgs commonargs;
|
||||
|
||||
libappletArgsCreate(&commonargs, 0x10000);
|
||||
libappletArgsSetPlayStartupSound(&commonargs, playStartupSound);
|
||||
|
||||
rc = libappletLaunch(AppletId_photoViewer, &commonargs, &arg, sizeof(arg), NULL, 0, NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result albumLaShowAlbumFiles(void) {
|
||||
return _albumLaShow(AlbumLaArg_ShowAlbumFiles, false);
|
||||
}
|
||||
|
||||
Result albumLaShowAllAlbumFiles(void) {
|
||||
return _albumLaShow(AlbumLaArg_ShowAllAlbumFiles, false);
|
||||
}
|
||||
|
||||
Result albumLaShowAllAlbumFilesForHomeMenu(void) {
|
||||
return _albumLaShow(AlbumLaArg_ShowAllAlbumFilesForHomeMenu, true);
|
||||
}
|
||||
|
||||
@ -214,7 +214,9 @@ Result errorSystemCreate(ErrorSystemConfig* c, const char* dialog_message, const
|
||||
|
||||
if (hosversionBefore(5,0,0)) {
|
||||
rc = setInitialize();
|
||||
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &c->arg.languageCode);
|
||||
u64 languageCode = 0;
|
||||
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &languageCode);
|
||||
if (R_SUCCEEDED(rc)) c->arg.languageCode = languageCode;
|
||||
setExit();
|
||||
}
|
||||
|
||||
@ -247,7 +249,9 @@ Result errorApplicationCreate(ErrorApplicationConfig* c, const char* dialog_mess
|
||||
|
||||
if (hosversionBefore(5,0,0)) {
|
||||
rc = setInitialize();
|
||||
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &c->arg.languageCode);
|
||||
u64 languageCode = 0;
|
||||
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &languageCode);
|
||||
if (R_SUCCEEDED(rc)) c->arg.languageCode = languageCode;
|
||||
setExit();
|
||||
}
|
||||
|
||||
|
||||
76
nx/source/applets/friends_la.c
Normal file
76
nx/source/applets/friends_la.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "services/acc.h"
|
||||
#include "services/applet.h"
|
||||
#include "applets/libapplet.h"
|
||||
#include "applets/friends_la.h"
|
||||
|
||||
static Result _friendsLaShow(const FriendsLaArg *arg, bool playStartupSound) {
|
||||
Result rc=0;
|
||||
Result rc2=0;
|
||||
size_t readsize=0;
|
||||
LibAppletArgs commonargs;
|
||||
|
||||
libappletArgsCreate(&commonargs, 0x1);
|
||||
libappletArgsSetPlayStartupSound(&commonargs, playStartupSound);
|
||||
|
||||
if (arg->type != FriendsLaArgType_StartSendingFriendRequest)
|
||||
rc = libappletLaunch(AppletId_myPage, &commonargs, arg, sizeof(*arg), NULL, 0, NULL);
|
||||
else {
|
||||
rc = libappletLaunch(AppletId_myPage, &commonargs, arg, sizeof(*arg), &rc2, sizeof(rc2), &readsize);
|
||||
if (R_SUCCEEDED(rc) && readsize!=sizeof(rc2)) rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
if (R_SUCCEEDED(rc)) rc = rc2;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _friendsLaShowSimple(FriendsLaArgType type, AccountUid *userID, bool playStartupSound) {
|
||||
FriendsLaArg arg = {.type = type, .userID = *userID};
|
||||
|
||||
return _friendsLaShow(&arg, playStartupSound);
|
||||
}
|
||||
|
||||
static Result _friendsLaShowAll(FriendsLaArgType type, AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName, bool playStartupSound) {
|
||||
FriendsLaArg arg = {.type = type, .userID = *userID, .networkServiceAccountId = networkServiceAccountId, .first_inAppScreenName = *first_inAppScreenName, .second_inAppScreenName = *second_inAppScreenName};
|
||||
|
||||
return _friendsLaShow(&arg, playStartupSound);
|
||||
}
|
||||
|
||||
Result friendsLaShowFriendList(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowFriendList, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowUserDetailInfo(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName) {
|
||||
return _friendsLaShowAll(FriendsLaArgType_ShowUserDetailInfo, userID, networkServiceAccountId, first_inAppScreenName, second_inAppScreenName, false);
|
||||
}
|
||||
|
||||
Result friendsLaStartSendingFriendRequest(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName) {
|
||||
return _friendsLaShowAll(FriendsLaArgType_StartSendingFriendRequest, userID, networkServiceAccountId, first_inAppScreenName, second_inAppScreenName, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowMethodsOfSendingFriendRequest(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowMethodsOfSendingFriendRequest, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaStartFacedFriendRequest(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_StartFacedFriendRequest, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowReceivedFriendRequestList(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowReceivedFriendRequestList, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowBlockedUserList(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowBlockedUserList, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowMyProfile(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowMyProfile, userID, false);
|
||||
}
|
||||
|
||||
Result friendsLaShowMyProfileForHomeMenu(AccountUid *userID) {
|
||||
return _friendsLaShowSimple(FriendsLaArgType_ShowMyProfile, userID, true);
|
||||
}
|
||||
|
||||
@ -350,11 +350,12 @@ Result webOfflineCreate(WebCommonConfig* config, WebDocumentKind docKind, u64 ti
|
||||
|
||||
Result webShareCreate(WebCommonConfig* config, WebShareStartPage page) {
|
||||
Result rc=0;
|
||||
AccountUid uid={0};
|
||||
|
||||
_webArgInitialize(config, AppletId_loginShare, WebShimKind_Share);
|
||||
|
||||
rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor);
|
||||
if (R_SUCCEEDED(rc)) rc = webConfigSetUserID(config, 0);
|
||||
if (R_SUCCEEDED(rc)) rc = webConfigSetUid(config, &uid);
|
||||
if (R_SUCCEEDED(rc)) rc = webConfigSetDisplayUrlKind(config, true);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1);
|
||||
@ -368,6 +369,7 @@ Result webShareCreate(WebCommonConfig* config, WebShareStartPage page) {
|
||||
|
||||
Result webLobbyCreate(WebCommonConfig* config) {
|
||||
Result rc=0;
|
||||
AccountUid uid={0};
|
||||
if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
_webArgInitialize(config, AppletId_loginShare, WebShimKind_Lobby);
|
||||
@ -375,7 +377,7 @@ Result webLobbyCreate(WebCommonConfig* config) {
|
||||
rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor);
|
||||
if (R_SUCCEEDED(rc) && config->version >= 0x30000) rc = webConfigSetPointer(config, false); // Added to user-process init with [3.0.0+].
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = webConfigSetUserID(config, 0);
|
||||
if (R_SUCCEEDED(rc)) rc = webConfigSetUid(config, &uid);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1);
|
||||
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown15, 1);
|
||||
@ -402,10 +404,10 @@ Result webConfigSetWhitelist(WebCommonConfig* config, const char* whitelist) {
|
||||
return _webConfigSetString(config, WebArgType_Whitelist, whitelist, 0x1000);
|
||||
}
|
||||
|
||||
Result webConfigSetUserID(WebCommonConfig* config, u128 userID) {
|
||||
Result webConfigSetUid(WebCommonConfig* config, AccountUid *uid) {
|
||||
WebShimKind shim = _webGetShimKind(config);
|
||||
if (shim != WebShimKind_Share && shim != WebShimKind_Web && shim != WebShimKind_Lobby) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
return _webTLVSet(config, WebArgType_UserID, &userID, sizeof(userID));
|
||||
return _webTLVSet(config, WebArgType_Uid, uid, sizeof(*uid));
|
||||
}
|
||||
|
||||
static Result _webConfigSetAlbumEntryTLV(WebCommonConfig* config, WebArgType type, const CapsAlbumEntry *entry) {
|
||||
|
||||
@ -5,11 +5,21 @@
|
||||
#include "runtime/hosversion.h"
|
||||
#include "display/binder.h"
|
||||
|
||||
static void* _binderIpcPrepareHeader(Binder* b, IpcCommand* cmd, size_t sizeof_raw)
|
||||
{
|
||||
return serviceIpcPrepareHeader(b->relay, cmd, sizeof_raw);
|
||||
}
|
||||
|
||||
static Result _binderIpcDispatch(Binder* b)
|
||||
{
|
||||
return serviceIpcDispatch(b->relay);
|
||||
}
|
||||
|
||||
static Result _binderIpcParse(Binder* b, IpcParsedCommand* r, size_t sizeof_raw)
|
||||
{
|
||||
return serviceIpcParse(b->relay, r, sizeof_raw);
|
||||
}
|
||||
|
||||
void binderCreate(Binder* b, s32 id)
|
||||
{
|
||||
memset(b, 0, sizeof(Binder));
|
||||
@ -41,12 +51,6 @@ Result binderInitSession(Binder* b, Service* relay)
|
||||
|
||||
b->initialized = true;
|
||||
|
||||
rc = ipcQueryPointerBufferSize(b->relay->handle, &b->ipc_buffer_size);
|
||||
if (R_FAILED(rc)) {
|
||||
binderClose(b);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Use TransactParcelAuto when available.
|
||||
if (hosversionAtLeast(3,0,0))
|
||||
b->has_transact_auto = true;
|
||||
@ -93,7 +97,7 @@ static Result _binderTransactParcel(
|
||||
ipcAddSendBuffer(&c, parcel_data, parcel_data_size, 0);
|
||||
ipcAddRecvBuffer(&c, parcel_reply, parcel_reply_size, 0);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->session_id = b->id;
|
||||
@ -104,12 +108,13 @@ static Result _binderTransactParcel(
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
} *resp;
|
||||
|
||||
_binderIpcParse(b, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
@ -137,10 +142,10 @@ static Result _binderTransactParcelAuto(
|
||||
u32 flags;
|
||||
} PACKED *raw;
|
||||
|
||||
ipcAddSendSmart(&c, b->ipc_buffer_size, parcel_data, parcel_data_size, 0);
|
||||
ipcAddRecvSmart(&c, b->ipc_buffer_size, parcel_reply, parcel_reply_size, 0);
|
||||
ipcAddSendSmart(&c, b->relay->pointer_buffer_size, parcel_data, parcel_data_size, 0);
|
||||
ipcAddRecvSmart(&c, b->relay->pointer_buffer_size, parcel_reply, parcel_reply_size, 0);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
raw->session_id = b->id;
|
||||
@ -151,12 +156,13 @@ static Result _binderTransactParcelAuto(
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
} *resp;
|
||||
|
||||
_binderIpcParse(b, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
@ -222,7 +228,7 @@ Result binderAdjustRefcount(Binder* b, s32 addval, s32 type)
|
||||
s32 type;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->session_id = b->id;
|
||||
@ -233,12 +239,13 @@ Result binderAdjustRefcount(Binder* b, s32 addval, s32 type)
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
} *resp;
|
||||
|
||||
_binderIpcParse(b, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
@ -261,7 +268,7 @@ Result binderGetNativeHandle(Binder* b, u32 inval, Event *event_out)
|
||||
u32 inval;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
@ -272,13 +279,14 @@ Result binderGetNativeHandle(Binder* b, u32 inval, Event *event_out)
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
_binderIpcParse(b, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
|
||||
@ -15,7 +15,7 @@ struct in_addr __nxlink_host;
|
||||
extern char* fake_heap_start;
|
||||
extern char* fake_heap_end;
|
||||
|
||||
extern u32 __argdata__;
|
||||
extern u8 __argdata__[];
|
||||
|
||||
static char* g_argv_empty = NULL;
|
||||
|
||||
@ -27,7 +27,7 @@ void argvSetup(void)
|
||||
MemoryInfo meminfo;
|
||||
u32 pageinfo=0;
|
||||
|
||||
u8 *argdata = (u8*)&__argdata__;
|
||||
u8 *argdata = __argdata__;
|
||||
u32 *arg32 = (u32*)argdata;
|
||||
u64 argdata_allocsize=0;
|
||||
u64 argdata_strsize=0;
|
||||
@ -94,7 +94,7 @@ void argvSetup(void)
|
||||
argstart = NULL;
|
||||
|
||||
for(argi=0; argi<argdata_strsize; argi++) {
|
||||
if (argstart == NULL && isspace(args[argi])) continue;
|
||||
if (argstart == NULL && isspace((unsigned char)args[argi])) continue;
|
||||
|
||||
if (argstart == NULL) {
|
||||
if (args[argi] == '"') {
|
||||
@ -112,7 +112,7 @@ void argvSetup(void)
|
||||
if (quote_flag) {
|
||||
if (args[argi] == '"') end_flag = 1;
|
||||
}
|
||||
else if (isspace(args[argi])) {
|
||||
else if (isspace((unsigned char)args[argi])) {
|
||||
end_flag = 1;
|
||||
}
|
||||
|
||||
|
||||
@ -7,10 +7,12 @@
|
||||
#include <sys/iosupport.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "runtime/devices/fs_dev.h"
|
||||
#include "runtime/util/utf.h"
|
||||
#include "services/fs.h"
|
||||
#include "services/time.h"
|
||||
|
||||
|
||||
/*! @internal
|
||||
@ -256,6 +258,28 @@ static ssize_t fsdev_convertfromfspath(uint8_t *out, uint8_t *in, size_t len)
|
||||
return strnlen((char*)out, len);
|
||||
}
|
||||
|
||||
static time_t fsdev_converttimetoutc(u64 timestamp)
|
||||
{
|
||||
// Parse timestamp into y/m/d h:m:s
|
||||
time_t posixtime = (time_t)timestamp;
|
||||
struct tm *t = gmtime(&posixtime);
|
||||
|
||||
// Convert time/date into an actual UTC POSIX timestamp using the system's timezone rules
|
||||
TimeCalendarTime caltime;
|
||||
caltime.year = 1900 + t->tm_year;
|
||||
caltime.month = 1 + t->tm_mon;
|
||||
caltime.day = t->tm_mday;
|
||||
caltime.hour = t->tm_hour;
|
||||
caltime.minute = t->tm_min;
|
||||
caltime.second = t->tm_sec;
|
||||
u64 new_timestamp;
|
||||
Result rc = timeToPosixTimeWithMyRule(&caltime, &new_timestamp, 1, NULL);
|
||||
if (R_SUCCEEDED(rc))
|
||||
posixtime = (time_t)new_timestamp;
|
||||
|
||||
return posixtime;
|
||||
}
|
||||
|
||||
extern int __system_argc;
|
||||
extern char** __system_argv;
|
||||
|
||||
@ -381,7 +405,7 @@ Result fsdevSetArchiveBit(const char *path) {
|
||||
return fsFsSetArchiveBit(&device->fs, fs_path);
|
||||
}
|
||||
|
||||
Result fsdevCreateFile(const char* path, size_t size, int flags) {
|
||||
Result fsdevCreateFile(const char* path, size_t size, u32 flags) {
|
||||
char fs_path[FS_MAX_PATH];
|
||||
fsdev_fsdevice *device = NULL;
|
||||
|
||||
@ -555,7 +579,7 @@ fsdev_open(struct _reent *r,
|
||||
{
|
||||
/* read-only: do not allow O_APPEND */
|
||||
case O_RDONLY:
|
||||
fsdev_flags |= FS_OPEN_READ;
|
||||
fsdev_flags |= FsOpenMode_Read;
|
||||
if(flags & O_APPEND)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
@ -565,12 +589,12 @@ fsdev_open(struct _reent *r,
|
||||
|
||||
/* write-only */
|
||||
case O_WRONLY:
|
||||
fsdev_flags |= FS_OPEN_WRITE | FS_OPEN_APPEND;
|
||||
fsdev_flags |= FsOpenMode_Write | FsOpenMode_Append;
|
||||
break;
|
||||
|
||||
/* read and write */
|
||||
case O_RDWR:
|
||||
fsdev_flags |= (FS_OPEN_READ | FS_OPEN_WRITE | FS_OPEN_APPEND);
|
||||
fsdev_flags |= (FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
|
||||
break;
|
||||
|
||||
/* an invalid option was supplied */
|
||||
@ -690,7 +714,7 @@ fsdev_write(struct _reent *r,
|
||||
}
|
||||
}
|
||||
|
||||
rc = fsFileWrite(&file->fd, file->offset, ptr, len, FS_WRITEOPTION_NONE);
|
||||
rc = fsFileWrite(&file->fd, file->offset, ptr, len, FsWriteOption_None);
|
||||
if(rc == 0xD401)
|
||||
return fsdev_write_safe(r, fd, ptr, len);
|
||||
if(R_FAILED(rc))
|
||||
@ -744,7 +768,7 @@ fsdev_write_safe(struct _reent *r,
|
||||
memcpy(tmp_buffer, ptr, toWrite);
|
||||
|
||||
/* write the data */
|
||||
rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite, FS_WRITEOPTION_NONE);
|
||||
rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite, FsWriteOption_None);
|
||||
|
||||
if(R_FAILED(rc))
|
||||
{
|
||||
@ -786,7 +810,7 @@ fsdev_read(struct _reent *r,
|
||||
size_t len)
|
||||
{
|
||||
Result rc;
|
||||
size_t bytes;
|
||||
u64 bytes;
|
||||
|
||||
/* get pointer to our data */
|
||||
fsdev_file_t *file = (fsdev_file_t*)fd;
|
||||
@ -799,7 +823,7 @@ fsdev_read(struct _reent *r,
|
||||
}
|
||||
|
||||
/* read the data */
|
||||
rc = fsFileRead(&file->fd, file->offset, ptr, len, FS_READOPTION_NONE, &bytes);
|
||||
rc = fsFileRead(&file->fd, file->offset, ptr, len, FsReadOption_None, &bytes);
|
||||
if(rc == 0xD401)
|
||||
return fsdev_read_safe(r, fd, ptr, len);
|
||||
if(R_SUCCEEDED(rc))
|
||||
@ -830,7 +854,7 @@ fsdev_read_safe(struct _reent *r,
|
||||
size_t len)
|
||||
{
|
||||
Result rc;
|
||||
size_t bytesRead = 0, bytes = 0;
|
||||
u64 bytesRead = 0, bytes = 0;
|
||||
|
||||
/* get pointer to our data */
|
||||
fsdev_file_t *file = (fsdev_file_t*)fd;
|
||||
@ -841,12 +865,12 @@ fsdev_read_safe(struct _reent *r,
|
||||
static __thread char tmp_buffer[8192];
|
||||
while(len > 0)
|
||||
{
|
||||
size_t toRead = len;
|
||||
u64 toRead = len;
|
||||
if(toRead > sizeof(tmp_buffer))
|
||||
toRead = sizeof(tmp_buffer);
|
||||
|
||||
/* read the data */
|
||||
rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, FS_READOPTION_NONE, &bytes);
|
||||
rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, FsReadOption_None, &bytes);
|
||||
|
||||
if(bytes > toRead)
|
||||
bytes = toRead;
|
||||
@ -965,9 +989,9 @@ fsdev_fstat(struct _reent *r,
|
||||
|
||||
if(file->timestamps.is_valid)
|
||||
{
|
||||
st->st_ctime = file->timestamps.created;
|
||||
st->st_mtime = file->timestamps.modified;
|
||||
st->st_atime = file->timestamps.accessed;
|
||||
st->st_ctime = fsdev_converttimetoutc(file->timestamps.created);
|
||||
st->st_mtime = fsdev_converttimetoutc(file->timestamps.modified);
|
||||
st->st_atime = fsdev_converttimetoutc(file->timestamps.accessed);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -998,7 +1022,7 @@ fsdev_stat(struct _reent *r,
|
||||
char fs_path[FS_MAX_PATH];
|
||||
fsdev_fsdevice *device = NULL;
|
||||
FsTimeStampRaw timestamps = {0};
|
||||
FsEntryType type;
|
||||
FsDirEntryType type;
|
||||
|
||||
if(fsdev_getfspath(r, file, &device, fs_path)==-1)
|
||||
return -1;
|
||||
@ -1006,9 +1030,9 @@ fsdev_stat(struct _reent *r,
|
||||
rc = fsFsGetEntryType(&device->fs, fs_path, &type);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
if(type == ENTRYTYPE_DIR)
|
||||
if(type == FsDirEntryType_Dir)
|
||||
{
|
||||
if(R_SUCCEEDED(rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fdir)))
|
||||
if(R_SUCCEEDED(rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fdir)))
|
||||
{
|
||||
memset(st, 0, sizeof(struct stat));
|
||||
st->st_nlink = 1;
|
||||
@ -1017,9 +1041,9 @@ fsdev_stat(struct _reent *r,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(type == ENTRYTYPE_FILE)
|
||||
else if(type == FsDirEntryType_File)
|
||||
{
|
||||
if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FS_OPEN_READ, &fd)))
|
||||
if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FsOpenMode_Read, &fd)))
|
||||
{
|
||||
fsdev_file_t tmpfd = { .fd = fd };
|
||||
ret = fsdev_fstat(r, &tmpfd, st);
|
||||
@ -1030,9 +1054,9 @@ fsdev_stat(struct _reent *r,
|
||||
rc = fsFsGetFileTimeStampRaw(&device->fs, fs_path, ×tamps);
|
||||
if(R_SUCCEEDED(rc) && timestamps.is_valid)
|
||||
{
|
||||
st->st_ctime = timestamps.created;
|
||||
st->st_mtime = timestamps.modified;
|
||||
st->st_atime = timestamps.accessed;
|
||||
st->st_ctime = fsdev_converttimetoutc(timestamps.created);
|
||||
st->st_mtime = fsdev_converttimetoutc(timestamps.modified);
|
||||
st->st_atime = fsdev_converttimetoutc(timestamps.accessed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1115,7 +1139,7 @@ fsdev_chdir(struct _reent *r,
|
||||
if(fsdev_getfspath(r, name, &device, fs_path)==-1)
|
||||
return -1;
|
||||
|
||||
rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fd);
|
||||
rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fd);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
fsDirClose(&fd);
|
||||
@ -1153,7 +1177,7 @@ fsdev_rename(struct _reent *r,
|
||||
const char *newName)
|
||||
{
|
||||
Result rc;
|
||||
FsEntryType type;
|
||||
FsDirEntryType type;
|
||||
fsdev_fsdevice *device_old = NULL, *device_new = NULL;
|
||||
char fs_path_old[FS_MAX_PATH];
|
||||
char fs_path_new[FS_MAX_PATH];
|
||||
@ -1173,13 +1197,13 @@ fsdev_rename(struct _reent *r,
|
||||
rc = fsFsGetEntryType(&device_old->fs, fs_path_old, &type);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
if(type == ENTRYTYPE_DIR)
|
||||
if(type == FsDirEntryType_Dir)
|
||||
{
|
||||
rc = fsFsRenameDirectory(&device_old->fs, fs_path_old, fs_path_new);
|
||||
if(R_SUCCEEDED(rc))
|
||||
return 0;
|
||||
}
|
||||
else if(type == ENTRYTYPE_FILE)
|
||||
else if(type == FsDirEntryType_File)
|
||||
{
|
||||
rc = fsFsRenameFile(&device_old->fs, fs_path_old, fs_path_new);
|
||||
if(R_SUCCEEDED(rc))
|
||||
@ -1251,7 +1275,7 @@ fsdev_diropen(struct _reent *r,
|
||||
fsdev_dir_t *dir = (fsdev_dir_t*)(dirState->dirStruct);
|
||||
|
||||
/* open the directory */
|
||||
rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fd);
|
||||
rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fd);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
dir->magic = FSDEV_DIRITER_MAGIC;
|
||||
@ -1299,7 +1323,7 @@ fsdev_dirnext(struct _reent *r,
|
||||
struct stat *filestat)
|
||||
{
|
||||
Result rc;
|
||||
size_t entries;
|
||||
u64 entries;
|
||||
ssize_t units;
|
||||
FsDirectoryEntry *entry;
|
||||
|
||||
@ -1342,9 +1366,9 @@ fsdev_dirnext(struct _reent *r,
|
||||
|
||||
/* fill in the stat info */
|
||||
filestat->st_ino = 0;
|
||||
if(entry->type == ENTRYTYPE_DIR)
|
||||
if(entry->type == FsDirEntryType_Dir)
|
||||
filestat->st_mode = S_IFDIR;
|
||||
else if(entry->type == ENTRYTYPE_FILE)
|
||||
else if(entry->type == FsDirEntryType_File)
|
||||
{
|
||||
filestat->st_mode = S_IFREG;
|
||||
filestat->st_size = entry->fileSize;
|
||||
|
||||
@ -52,11 +52,11 @@ static char __thread __component[PATH_MAX+1];
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size)
|
||||
{
|
||||
u64 pos = mount->offset + offset;
|
||||
size_t read = 0;
|
||||
u64 read = 0;
|
||||
Result rc = 0;
|
||||
if(mount->fd_type == RomfsSource_FsFile)
|
||||
{
|
||||
rc = fsFileRead(&mount->fd, pos, buffer, size, FS_READOPTION_NONE, &read);
|
||||
rc = fsFileRead(&mount->fd, pos, buffer, size, FsReadOption_None, &read);
|
||||
}
|
||||
else if(mount->fd_type == RomfsSource_FsStorage)
|
||||
{
|
||||
@ -170,7 +170,7 @@ static romfs_mount *romfsFindMount(const char *name)
|
||||
}
|
||||
else if(mount->setup) //Find the mount with the input name.
|
||||
{
|
||||
if(strncmp(mount->name, name, strlen(mount->name))==0)
|
||||
if(strncmp(mount->name, name, sizeof(mount->name))==0)
|
||||
return mount;
|
||||
}
|
||||
}
|
||||
@ -244,7 +244,7 @@ Result romfsMount(const char *name)
|
||||
return 2;
|
||||
}
|
||||
|
||||
Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd);
|
||||
Result rc = fsFsOpenFile(sdfs, filename, FsOpenMode_Read, &mount->fd);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
@ -344,7 +344,7 @@ Result romfsMountFromFsdev(const char *path, u64 offset, const char *name)
|
||||
mount->fd_type = RomfsSource_FsFile;
|
||||
mount->offset = offset;
|
||||
|
||||
Result rc = fsFsOpenFile(tmpfs, filepath, FS_OPEN_READ, &mount->fd);
|
||||
Result rc = fsFsOpenFile(tmpfs, filepath, FsOpenMode_Read, &mount->fd);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "services/sm.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/acc.h"
|
||||
|
||||
void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr);
|
||||
|
||||
@ -23,7 +24,7 @@ static char* g_nextLoadArgv = NULL;
|
||||
static Result g_lastLoadResult = 0;
|
||||
static bool g_hasRandomSeed = false;
|
||||
static u64 g_randomSeed[2] = { 0, 0 };
|
||||
static u128* g_userIdStorage = NULL;
|
||||
static AccountUid* g_userIdStorage = NULL;
|
||||
|
||||
extern __attribute__((weak)) u32 __nx_applet_type;
|
||||
|
||||
@ -104,7 +105,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
|
||||
break;
|
||||
|
||||
case EntryType_UserIdStorage:
|
||||
g_userIdStorage = (u128*)(uintptr_t)ent->Value[0];
|
||||
g_userIdStorage = (AccountUid*)(uintptr_t)ent->Value[0];
|
||||
break;
|
||||
|
||||
case EntryType_HosVersion:
|
||||
@ -222,6 +223,6 @@ void envGetRandomSeed(u64 out[2]) {
|
||||
out[1] = g_randomSeed[1];
|
||||
}
|
||||
|
||||
u128* envGetUserIdStorage(void) {
|
||||
AccountUid* envGetUserIdStorage(void) {
|
||||
return g_userIdStorage;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ static u32 g_nacpLanguageTable[15] = {
|
||||
Result nacpGetLanguageEntry(NacpStruct* nacp, NacpLanguageEntry** langentry) {
|
||||
Result rc=0;
|
||||
u64 LanguageCode=0;
|
||||
s32 Language=0;
|
||||
SetLanguage Language=0;
|
||||
NacpLanguageEntry *entry = NULL;
|
||||
u32 i=0;
|
||||
|
||||
|
||||
@ -1,37 +1,44 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "service_guard.h"
|
||||
#include "services/acc.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/applet.h"
|
||||
#include "runtime/env.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
static AccountServiceType g_accServiceType = AccountServiceType_NotInitialized;
|
||||
static Service g_accSrv;
|
||||
static u64 g_refCnt;
|
||||
static u128 g_accPreselectedUserID;
|
||||
static AccountUid g_accPreselectedUserID;
|
||||
static bool g_accPreselectedUserInitialized;
|
||||
|
||||
static Result _accountInitializeApplicationInfo(void);
|
||||
|
||||
static Result _accountGetPreselectedUser(u128 *userID);
|
||||
static Result _accountGetPreselectedUser(AccountUid *userID);
|
||||
|
||||
Result accountInitialize(void)
|
||||
{
|
||||
NX_GENERATE_SERVICE_GUARD(account);
|
||||
|
||||
void accountSetServiceType(AccountServiceType serviceType) {
|
||||
g_accServiceType = serviceType;
|
||||
}
|
||||
|
||||
Result _accountInitialize(void) {
|
||||
Result rc=0;
|
||||
Result rc2=0;
|
||||
u128 *userIdEnv = envGetUserIdStorage();
|
||||
AccountUid *userIdEnv = envGetUserIdStorage();
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_accSrv))
|
||||
return 0;
|
||||
|
||||
rc = smGetService(&g_accSrv, "acc:u1");
|
||||
if (R_FAILED(rc)) {
|
||||
rc = smGetService(&g_accSrv, "acc:u0");
|
||||
if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo();
|
||||
switch (g_accServiceType) {
|
||||
case AccountServiceType_NotInitialized:
|
||||
case AccountServiceType_Application:
|
||||
g_accServiceType = AccountServiceType_Application;
|
||||
rc = smGetService(&g_accSrv, "acc:u0");
|
||||
if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo();
|
||||
break;
|
||||
case AccountServiceType_System:
|
||||
rc = smGetService(&g_accSrv, "acc:u1");
|
||||
break;
|
||||
case AccountServiceType_Administrator:
|
||||
rc = smGetService(&g_accSrv, "acc:su");
|
||||
break;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
@ -42,354 +49,128 @@ Result accountInitialize(void)
|
||||
}
|
||||
else if (userIdEnv) {
|
||||
g_accPreselectedUserID = *userIdEnv;
|
||||
if (g_accPreselectedUserID) g_accPreselectedUserInitialized = true;
|
||||
if (accountUidIsValid(&g_accPreselectedUserID)) g_accPreselectedUserInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) accountExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void accountExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
serviceClose(&g_accSrv);
|
||||
void _accountCleanup(void) {
|
||||
serviceClose(&g_accSrv);
|
||||
g_accServiceType = AccountServiceType_NotInitialized;
|
||||
}
|
||||
|
||||
Service* accountGetServiceSession(void) {
|
||||
return &g_accSrv;
|
||||
}
|
||||
|
||||
static Result _accountCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _accountInitializeApplicationInfo(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid_placeholder;
|
||||
} *raw;
|
||||
|
||||
ipcSendPid(&c);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_accSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionBefore(6,0,0) ? 100 : 140;
|
||||
raw->pid_placeholder = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_accSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
u64 pid_placeholder=0;
|
||||
return serviceDispatchIn(&g_accSrv, hosversionBefore(6,0,0) ? 100 : 140, pid_placeholder,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result accountGetUserCount(s32* user_count)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 user_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*user_count = resp->user_count;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetUserCount(s32* user_count) {
|
||||
return _accountCmdNoInOutU32(&g_accSrv, (u32*)user_count, 0);
|
||||
}
|
||||
|
||||
static Result _accountListAllUsers(u128* userIDs)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
static Result _accountListAllUsers(AccountUid* userIDs) {
|
||||
return serviceDispatch(&g_accSrv, 2,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { userIDs, sizeof(AccountUid)*ACC_USER_LIST_SIZE } },
|
||||
);
|
||||
}
|
||||
|
||||
Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total) {
|
||||
Result rc=0;
|
||||
|
||||
size_t bufsize = ACC_USER_LIST_SIZE * sizeof(u128);
|
||||
|
||||
ipcAddRecvStatic(&c, userIDs, bufsize, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total)
|
||||
{
|
||||
Result rc=0;
|
||||
u128 temp_userIDs[ACC_USER_LIST_SIZE];
|
||||
AccountUid temp_userIDs[ACC_USER_LIST_SIZE];
|
||||
memset(temp_userIDs, 0, sizeof(temp_userIDs));
|
||||
|
||||
rc = _accountListAllUsers(temp_userIDs);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
size_t total_userIDs;
|
||||
for (total_userIDs = 0; total_userIDs < ACC_USER_LIST_SIZE; total_userIDs++) {
|
||||
if (!temp_userIDs[total_userIDs])
|
||||
break;
|
||||
s32 total_userIDs;
|
||||
for (total_userIDs=0; total_userIDs<ACC_USER_LIST_SIZE; total_userIDs++) {
|
||||
if (!accountUidIsValid(&temp_userIDs[total_userIDs])) break;
|
||||
}
|
||||
|
||||
if (max_userIDs > total_userIDs) {
|
||||
max_userIDs = total_userIDs;
|
||||
}
|
||||
|
||||
memcpy(userIDs, temp_userIDs, sizeof(u128) * max_userIDs);
|
||||
memcpy(userIDs, temp_userIDs, sizeof(AccountUid)*max_userIDs);
|
||||
*actual_total = max_userIDs;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u128 userID;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && userID) {
|
||||
*userID = resp->userID;
|
||||
if (account_selected) {
|
||||
*account_selected = 0;
|
||||
if (*userID != 0) *account_selected = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetLastOpenedUser(AccountUid *userID) {
|
||||
return serviceDispatchOut(&g_accSrv, 4, *userID);
|
||||
}
|
||||
|
||||
Result accountGetProfile(AccountProfile* out, u128 userID) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u128 userID;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
raw->userID = userID;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&out->s, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetProfile(AccountProfile* out, const AccountUid *userID) {
|
||||
return serviceDispatchIn(&g_accSrv, 5, *userID,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s,
|
||||
);
|
||||
}
|
||||
|
||||
//IProfile implementation
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
if (userdata) ipcAddRecvStatic(&c, userdata, sizeof(AccountUserData), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = userdata==NULL ? 1 : 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
AccountProfileBase profilebase;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && profilebase) memcpy(profilebase, &resp->profilebase, sizeof(AccountProfileBase));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 10;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 image_size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*image_size = resp->image_size;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buf, len, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 11;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 image_size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*image_size = resp->image_size;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
// IProfile
|
||||
|
||||
void accountProfileClose(AccountProfile* profile) {
|
||||
serviceClose(&profile->s);
|
||||
}
|
||||
|
||||
static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
static Result _accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
return serviceDispatchOut(&profile->s, 0, *profilebase,
|
||||
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { userdata, sizeof(AccountUserData) } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _accountProfileGetBase(AccountProfile* profile, AccountProfileBase* profilebase) {
|
||||
return serviceDispatchOut(&profile->s, 1, *profilebase);
|
||||
}
|
||||
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
Result rc=0;
|
||||
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
if (userdata)
|
||||
rc = _accountProfileGet(profile, userdata, profilebase);
|
||||
else
|
||||
rc = _accountProfileGetBase(profile, profilebase);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size) {
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _accountCmdNoInOutU32(&profile->s, image_size, 10);
|
||||
}
|
||||
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size) {
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return serviceDispatchOut(&profile->s, 11, *image_size,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { buf, len } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _accountGetPreselectedUser(AccountUid *userID) {
|
||||
Result rc=0;
|
||||
AppletStorage storage;
|
||||
s64 tmpsize=0;
|
||||
@ -398,9 +179,9 @@ static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
u32 magicnum;//These two fields must match fixed values.
|
||||
u8 unk_x4;
|
||||
u8 pad[3];
|
||||
u128 userID;
|
||||
AccountUid userID;
|
||||
u8 unk_x18[0x70];//unused
|
||||
} PACKED storagedata;
|
||||
} storagedata;
|
||||
|
||||
memset(&storagedata, 0, sizeof(storagedata));
|
||||
|
||||
@ -424,7 +205,7 @@ static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountGetPreselectedUser(u128 *userID) {
|
||||
Result accountGetPreselectedUser(AccountUid *userID) {
|
||||
if (!g_accPreselectedUserInitialized) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
*userID = g_accPreselectedUserID;
|
||||
|
||||
@ -1,153 +1,55 @@
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "services/apm.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_apmSrv;
|
||||
static Service g_apmISession;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static Result _apmGetSession(Service* srv, Service* srv_out, u64 cmd_id);
|
||||
static Result _apmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
|
||||
|
||||
Result apmInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
NX_GENERATE_SERVICE_GUARD(apm);
|
||||
|
||||
if (serviceIsActive(&g_apmSrv))
|
||||
return 0;
|
||||
|
||||
Result rc = 0;
|
||||
|
||||
rc = smGetService(&g_apmSrv, "apm");
|
||||
Result _apmInitialize(void) {
|
||||
Result rc = smGetService(&g_apmSrv, "apm");
|
||||
|
||||
// OpenSession.
|
||||
// Official sw doesn't open this until using commands which need it, when it wasn't already opened.
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _apmGetSession(&g_apmSrv, &g_apmISession, 0);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
apmExit();
|
||||
if (R_SUCCEEDED(rc)) rc = _apmCmdGetSession(&g_apmSrv, &g_apmISession, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void apmExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_apmISession);
|
||||
serviceClose(&g_apmSrv);
|
||||
}
|
||||
void _apmCleanup(void) {
|
||||
serviceClose(&g_apmISession);
|
||||
serviceClose(&g_apmSrv);
|
||||
}
|
||||
|
||||
Service* apmGetServiceSession(void) {
|
||||
return &g_apmSrv;
|
||||
}
|
||||
|
||||
static Result _apmGetSession(Service* srv, Service* srv_out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(srv_out, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Service* apmGetServiceSession_Session(void) {
|
||||
return &g_apmISession;
|
||||
}
|
||||
|
||||
Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
static Result _apmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
Result apmSetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 PerformanceConfiguration) {
|
||||
const struct {
|
||||
u32 PerformanceMode;
|
||||
u32 PerformanceConfiguration;
|
||||
} *raw;
|
||||
} in = { PerformanceMode, PerformanceConfiguration };
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->PerformanceMode = PerformanceMode;
|
||||
raw->PerformanceConfiguration = PerformanceConfiguration;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_apmISession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_apmISession, 0, in);
|
||||
}
|
||||
|
||||
Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 PerformanceMode;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->PerformanceMode = PerformanceMode;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_apmISession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 PerformanceConfiguration;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && PerformanceConfiguration) *PerformanceConfiguration = resp->PerformanceConfiguration;
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result apmGetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 *PerformanceConfiguration) {
|
||||
u32 tmp=PerformanceMode;
|
||||
return serviceDispatchInOut(&g_apmISession, 1, tmp, *PerformanceConfiguration);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
115
nx/source/services/async.c
Normal file
115
nx/source/services/async.c
Normal file
@ -0,0 +1,115 @@
|
||||
#include "sf/service.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/async.h"
|
||||
#include "applets/error.h"
|
||||
|
||||
static Result _asyncCmdNoIO(Service* srv, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id);
|
||||
}
|
||||
|
||||
static Result _asyncCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _asyncCmdNoInOutBuf(Service* srv, void* buffer, size_t size, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
// IAsyncValue
|
||||
|
||||
void asyncValueClose(AsyncValue *a) {
|
||||
if (serviceIsActive(&a->s)) {
|
||||
asyncValueCancel(a); // Official sw ignores rc from this prior to waiting on the event.
|
||||
asyncValueWait(a, U64_MAX);
|
||||
}
|
||||
|
||||
serviceClose(&a->s);
|
||||
eventClose(&a->event);
|
||||
}
|
||||
|
||||
Result asyncValueWait(AsyncValue *a, u64 timeout) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return eventWait(&a->event, timeout);
|
||||
}
|
||||
|
||||
Result asyncValueGetSize(AsyncValue *a, u64 *size) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _asyncCmdNoInOutU64(&a->s, size, 0);
|
||||
}
|
||||
|
||||
Result asyncValueGet(AsyncValue *a, void* buffer, size_t size) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
Result rc = asyncValueWait(a, U64_MAX);
|
||||
if (R_SUCCEEDED(rc)) rc = _asyncCmdNoInOutBuf(&a->s, buffer, size, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result asyncValueCancel(AsyncValue *a) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _asyncCmdNoIO(&a->s, 2);
|
||||
}
|
||||
|
||||
Result asyncValueGetErrorContext(AsyncValue *a, ErrorContext *context) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
if (hosversionBefore(4,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
return _asyncCmdNoInOutBuf(&a->s, context, sizeof(*context), 3);
|
||||
}
|
||||
|
||||
// AsyncResult
|
||||
|
||||
void asyncResultClose(AsyncResult *a) {
|
||||
if (serviceIsActive(&a->s)) {
|
||||
asyncResultCancel(a); // Official sw ignores rc from this prior to waiting on the event.
|
||||
asyncResultWait(a, U64_MAX);
|
||||
}
|
||||
|
||||
serviceClose(&a->s);
|
||||
eventClose(&a->event);
|
||||
}
|
||||
|
||||
Result asyncResultWait(AsyncResult *a, u64 timeout) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return eventWait(&a->event, timeout);
|
||||
}
|
||||
|
||||
Result asyncResultGet(AsyncResult *a) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
Result rc = asyncResultWait(a, U64_MAX);
|
||||
if (R_SUCCEEDED(rc)) rc = _asyncCmdNoIO(&a->s, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result asyncResultCancel(AsyncResult *a) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _asyncCmdNoIO(&a->s, 1);
|
||||
}
|
||||
|
||||
Result asyncResultGetErrorContext(AsyncResult *a, ErrorContext *context) {
|
||||
if (!serviceIsActive(&a->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
if (hosversionBefore(4,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
return _asyncCmdNoInOutBuf(&a->s, context, sizeof(*context), 2);
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
|
||||
static Service g_auddevIAudioDevice;
|
||||
static u64 g_auddevRefCnt;
|
||||
static size_t g_auddevIpcBufferSize;
|
||||
|
||||
static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid);
|
||||
|
||||
@ -32,8 +31,6 @@ Result auddevInitialize(void) {
|
||||
rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid);
|
||||
|
||||
serviceClose(&audrenMgrSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_auddevIAudioDevice.handle, &g_auddevIpcBufferSize);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) auddevExit();
|
||||
@ -102,7 +99,7 @@ Result auddevListAudioDeviceName(AudioDeviceName *DeviceNames, s32 max_names, s3
|
||||
} *raw;
|
||||
|
||||
if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, BufferType_Normal);
|
||||
if (new_cmd) ipcAddRecvSmart(&c, g_auddevIpcBufferSize, DeviceNames, sizeof(AudioDeviceName) * max_names, 0);
|
||||
if (new_cmd) ipcAddRecvSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceNames, sizeof(AudioDeviceName) * max_names, 0);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||
|
||||
@ -144,7 +141,7 @@ Result auddevSetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
|
||||
} *raw;
|
||||
|
||||
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0);
|
||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||
|
||||
@ -183,7 +180,7 @@ Result auddevGetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
|
||||
} *raw;
|
||||
|
||||
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0);
|
||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@ __thread Result g_bsdResult;
|
||||
__thread int g_bsdErrno;
|
||||
|
||||
static Service g_bsdSrv;
|
||||
static size_t g_bsdSrvIpcBufferSize;
|
||||
static Service g_bsdMonitor;
|
||||
static u64 g_bsdClientPid = -1;
|
||||
|
||||
@ -189,7 +188,7 @@ static int _bsdNameGetterCommand(u32 cmd_id, int sockfd, struct sockaddr *addr,
|
||||
|
||||
socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen;
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, addr, maxaddrlen, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, addr, maxaddrlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -247,9 +246,6 @@ Result bsdInitialize(const BsdInitConfig *config) {
|
||||
}
|
||||
if(R_FAILED(rc)) goto error;
|
||||
|
||||
rc = ipcQueryPointerBufferSize(g_bsdSrv.handle, &g_bsdSrvIpcBufferSize);
|
||||
if(R_FAILED(rc)) goto error;
|
||||
|
||||
rc = smGetService(&g_bsdMonitor, bsd_srv);
|
||||
if(R_FAILED(rc)) goto error;
|
||||
|
||||
@ -270,7 +266,6 @@ error:
|
||||
}
|
||||
|
||||
void bsdExit(void) {
|
||||
g_bsdSrvIpcBufferSize = 0;
|
||||
g_bsdClientPid = 0;
|
||||
serviceClose(&g_bsdMonitor);
|
||||
serviceClose(&g_bsdSrv);
|
||||
@ -294,7 +289,7 @@ int bsdOpen(const char *pathname, int flags) {
|
||||
ipcInitialize(&c);
|
||||
|
||||
size_t pathlen = strlen(pathname) + 1;
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, pathname, pathlen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, pathname, pathlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -315,15 +310,15 @@ int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, st
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||
|
||||
|
||||
struct {
|
||||
@ -349,8 +344,8 @@ int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -375,10 +370,10 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
|
||||
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, name, 4 * namelen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, newp, newlen, 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, name, 4 * namelen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, newp, newlen, 1);
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, oldp, inlen, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, oldp, inlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -405,7 +400,7 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
|
||||
ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -430,8 +425,8 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
|
||||
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, src_addr, inaddrlen, 1);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, src_addr, inaddrlen, 1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -453,7 +448,7 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
|
||||
ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -475,8 +470,8 @@ ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
|
||||
ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, dest_addr, addrlen, 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, dest_addr, addrlen, 1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -502,7 +497,7 @@ int bsdAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -522,7 +517,7 @@ int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -553,7 +548,7 @@ int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *o
|
||||
|
||||
socklen_t inoptlen = optlen == NULL ? 0 : *optlen;
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, optval, inoptlen, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, optval, inoptlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -645,15 +640,15 @@ int bsdIoctl(int fd, int request, void *data) {
|
||||
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in1, in1sz, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in2, in2sz, 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in3, in3sz, 2);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in4, in4sz, 3);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in1, in1sz, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in2, in2sz, 1);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in3, in3sz, 2);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in4, in4sz, 3);
|
||||
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out1, out1sz, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out2, out2sz, 1);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out3, out3sz, 2);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out4, out4sz, 3);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out1, out1sz, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out2, out2sz, 1);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out3, out3sz, 2);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out4, out4sz, 3);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -711,7 +706,7 @@ int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, sockle
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, optval, optlen, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, optval, optlen, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -775,7 +770,7 @@ int bsdShutdownAllSockets(int how) {
|
||||
ssize_t bsdWrite(int fd, const void *buf, size_t count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0);
|
||||
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -795,7 +790,7 @@ ssize_t bsdWrite(int fd, const void *buf, size_t count) {
|
||||
ssize_t bsdRead(int fd, void *buf, size_t count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0);
|
||||
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
|
||||
17
nx/source/services/caps.c
Normal file
17
nx/source/services/caps.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "kernel/event.h"
|
||||
#include "kernel/tmem.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/caps.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
u64 capsGetShimLibraryVersion(void) {
|
||||
u64 version=1; // [7.0.0-8.1.0]
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
@ -1,85 +1,45 @@
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/caps.h"
|
||||
#include "services/capssc.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_capsscSrv;
|
||||
static u64 g_capsscRefCnt;
|
||||
|
||||
Result capsscInitialize(void) {
|
||||
NX_GENERATE_SERVICE_GUARD(capssc);
|
||||
|
||||
Result _capsscInitialize(void) {
|
||||
Result rc=0;
|
||||
|
||||
atomicIncrement64(&g_capsscRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_capsscSrv))
|
||||
return 0;
|
||||
|
||||
if (hosversionBefore(2,0,0))
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsscSrv, "caps:sc");
|
||||
|
||||
if (R_FAILED(rc)) capsscExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void capsscExit(void) {
|
||||
if (atomicDecrement64(&g_capsscRefCnt) == 0)
|
||||
serviceClose(&g_capsscSrv);
|
||||
void _capsscCleanup(void) {
|
||||
serviceClose(&g_capsscSrv);
|
||||
}
|
||||
|
||||
Service* capsscGetServiceSession(void) {
|
||||
return &g_capsscSrv;
|
||||
}
|
||||
|
||||
Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
Result capsscCaptureRawImageWithTimeout(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout) {
|
||||
const struct {
|
||||
u32 inval;
|
||||
u64 width;
|
||||
u64 height;
|
||||
s64 buffer_count;
|
||||
s64 buffer_index;
|
||||
u64 timeout;
|
||||
} *raw;
|
||||
} in = { inval, width, height, buffer_count, buffer_index, timeout };
|
||||
|
||||
ipcAddRecvBuffer(&c, buf, size, 1);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_capsscSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->inval = inval;
|
||||
raw->width = width;
|
||||
raw->height = height;
|
||||
raw->buffer_count = buffer_count;
|
||||
raw->buffer_index = buffer_index;
|
||||
raw->timeout = timeout;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_capsscSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_capsscSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_capsscSrv, 2, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { buf, size } },
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,101 +1,157 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/caps.h"
|
||||
#include "services/capssu.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/acc.h"
|
||||
|
||||
static Service g_capssuSrv;
|
||||
static u64 g_capssuRefCnt;
|
||||
|
||||
Result capssuInitialize(void) {
|
||||
static Result _capssuSetShimLibraryVersion(u64 version);
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(capssu);
|
||||
|
||||
Result _capssuInitialize(void) {
|
||||
Result rc=0;
|
||||
|
||||
atomicIncrement64(&g_capssuRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_capssuSrv))
|
||||
return 0;
|
||||
|
||||
if (hosversionBefore(4,0,0))
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capssuSrv, "caps:su");
|
||||
|
||||
if (R_FAILED(rc)) capssuExit();
|
||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capssuSetShimLibraryVersion(capsGetShimLibraryVersion());
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void capssuExit(void) {
|
||||
if (atomicDecrement64(&g_capssuRefCnt) == 0)
|
||||
serviceClose(&g_capssuSrv);
|
||||
void _capssuCleanup(void) {
|
||||
serviceClose(&g_capssuSrv);
|
||||
}
|
||||
|
||||
Service* capssuGetServiceSession(void) {
|
||||
return &g_capssuSrv;
|
||||
}
|
||||
|
||||
static Result _capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) {
|
||||
static Result _capssuSetShimLibraryVersion(u64 version) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
CapsScreenShotAttribute attr;
|
||||
u32 unk;
|
||||
const struct {
|
||||
u64 version;
|
||||
u64 AppletResourceUserId;
|
||||
} *raw;
|
||||
} in = { version, AppletResourceUserId };
|
||||
|
||||
ipcSendPid(&c);
|
||||
ipcAddSendBuffer(&c, buffer, size, 1);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_capssuSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 203;
|
||||
raw->attr = *attr;
|
||||
raw->unk = unk;
|
||||
raw->AppletResourceUserId = AppletResourceUserId;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_capssuSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
CapsApplicationAlbumEntry out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_capssuSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) *out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_capssuSrv, 32, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out) {
|
||||
static Result _capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsScreenShotAttribute attr;
|
||||
u32 reportoption;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *attr, reportoption, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchInOut(&g_capssuSrv, 203, in, *out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||
.buffers = { { buffer, size } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capssuSaveScreenShotEx(u32 cmd_id, bool pid, const void* argbuf, size_t argbuf_size, const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsScreenShotAttribute attr;
|
||||
u32 reportoption;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *attr, reportoption, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchInOut(&g_capssuSrv, cmd_id, in, *out,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
},
|
||||
.buffers = {
|
||||
{ argbuf, argbuf_size },
|
||||
{ buffer, size },
|
||||
},
|
||||
.in_send_pid = pid,
|
||||
);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShot(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, CapsApplicationAlbumEntry *out) {
|
||||
CapsScreenShotAttribute attr;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.unk_x0 = attr_val;
|
||||
attr.orientation = orientation;
|
||||
attr.unk_xc = 1;
|
||||
|
||||
return _capssuSaveScreenShotEx0(buffer, size, &attr, unk, out);
|
||||
return _capssuSaveScreenShotEx0(buffer, size, &attr, reportoption, out);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) {
|
||||
return _capssuSaveScreenShotEx0(buffer, size, attr, unk, out);
|
||||
Result capssuSaveScreenShotWithUserData(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const void* userdata, size_t userdata_size, CapsApplicationAlbumEntry *out) {
|
||||
CapsScreenShotAttribute attr;
|
||||
CapsApplicationData appdata;
|
||||
|
||||
if (userdata_size > sizeof(appdata).userdata)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.orientation = orientation;
|
||||
attr.unk_xc = 1;
|
||||
|
||||
memset(&appdata, 0, sizeof(appdata));
|
||||
if (userdata && userdata_size) memcpy(appdata.userdata, userdata, userdata_size);
|
||||
appdata.size = userdata_size;
|
||||
|
||||
return capssuSaveScreenShotEx1(buffer, size, &attr, reportoption, &appdata, out);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShotWithUserIds(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const AccountUid* userIDs, size_t userID_count, CapsApplicationAlbumEntry *out) {
|
||||
CapsScreenShotAttribute attr;
|
||||
CapsUserIdList list;
|
||||
|
||||
if (userID_count > ACC_USER_LIST_SIZE)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.orientation = orientation;
|
||||
attr.unk_xc = 1;
|
||||
|
||||
memset(&list, 0, sizeof(list));
|
||||
if (userIDs && userID_count) memcpy(list.userIDs, userIDs, userID_count*sizeof(AccountUid));
|
||||
list.count = userID_count;
|
||||
|
||||
return capssuSaveScreenShotEx2(buffer, size, &attr, reportoption, &list, out);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
|
||||
return _capssuSaveScreenShotEx0(buffer, size, attr, reportoption, out);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationData *appdata, CapsApplicationAlbumEntry *out) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
return _capssuSaveScreenShotEx(205, true, appdata, sizeof(*appdata), buffer, size, attr, reportoption, out);
|
||||
}
|
||||
|
||||
Result capssuSaveScreenShotEx2(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsUserIdList *list, CapsApplicationAlbumEntry *out) {
|
||||
if (hosversionBefore(6,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
return _capssuSaveScreenShotEx(210, false, list, sizeof(*list), buffer, size, attr, reportoption, out);
|
||||
}
|
||||
|
||||
|
||||
380
nx/source/services/capsu.c
Normal file
380
nx/source/services/capsu.c
Normal file
@ -0,0 +1,380 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/caps.h"
|
||||
#include "services/capsu.h"
|
||||
#include "services/acc.h"
|
||||
|
||||
static Service g_capsuSrv;
|
||||
static Service g_capsuAccessor;
|
||||
|
||||
static Result _capsuSetShimLibraryVersion(u64 version);
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(capsu);
|
||||
|
||||
Result _capsuInitialize(void) {
|
||||
Result rc=0;
|
||||
|
||||
if (hosversionBefore(5,0,0))
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsuSrv, "caps:u");
|
||||
|
||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capsuSetShimLibraryVersion(capsGetShimLibraryVersion());
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void _capsuCleanup(void) {
|
||||
serviceClose(&g_capsuAccessor);
|
||||
serviceClose(&g_capsuSrv);
|
||||
}
|
||||
|
||||
Service* capsuGetServiceSession(void) {
|
||||
return &g_capsuSrv;
|
||||
}
|
||||
|
||||
Service* capsuGetServiceSession_Accessor(void) {
|
||||
return &g_capsuAccessor;
|
||||
}
|
||||
|
||||
static Result _capsuCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result _capsuSetShimLibraryVersion(u64 version) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u64 version;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { version, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchIn(&g_capsuSrv, 32, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuGetAlbumFileList0AafeAruidDeprecated(void* entries, size_t entrysize, s32 count, u8 type, u64 start_timestamp, u64 end_timestamp, s32 *total_entries) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u8 type;
|
||||
u64 start_timestamp;
|
||||
u64 end_timestamp;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { type, start_timestamp, end_timestamp, AppletResourceUserId };
|
||||
|
||||
u64 total_out=0;
|
||||
Result rc = serviceDispatchInOut(&g_capsuSrv, 102, in, total_out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { entries, count*entrysize } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _capsuDeleteAlbumFileByAruid(u32 cmd_id, u8 type, const CapsApplicationAlbumFileEntry *entry) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u8 type;
|
||||
CapsApplicationAlbumFileEntry entry;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { type, *entry, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchIn(&g_capsuSrv, 103, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuGetAlbumFileSizeByAruid(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsApplicationAlbumFileEntry entry;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *entry, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchInOut(&g_capsuSrv, 104, in, *size,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuPrecheckToCreateContentsByAruid(u8 type, u64 unk) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u8 type;
|
||||
u64 unk;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { type, unk, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchIn(&g_capsuSrv, 130, in,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuLoadAlbumScreenShotImageByAruid(u32 cmd_id, CapsLoadAlbumScreenShotImageOutputForApplication *out, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsApplicationAlbumFileEntry entry;
|
||||
CapsScreenShotDecodeOption option;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *entry, *option, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchIn(&g_capsuSrv, cmd_id, in,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ out, sizeof(*out) },
|
||||
{ image, image_size },
|
||||
{ workbuf, workbuf_size },
|
||||
},
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuGetAlbumFileListAaeAruid(u32 cmd_id, void* entries, size_t entrysize, s32 count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u8 type;
|
||||
CapsAlbumFileDateTime start_datetime;
|
||||
CapsAlbumFileDateTime end_datetime;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { type, *start_datetime, *end_datetime, AppletResourceUserId };
|
||||
|
||||
u64 total_out=0;
|
||||
Result rc = serviceDispatchInOut(&g_capsuSrv, cmd_id, in, total_out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { entries, count*entrysize } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _capsuGetAlbumFileListAaeUidAruid(u32 cmd_id, void* entries, size_t entrysize, s32 count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
u8 type;
|
||||
CapsAlbumFileDateTime start_datetime;
|
||||
CapsAlbumFileDateTime end_datetime;
|
||||
AccountUid userID;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { type, *start_datetime, *end_datetime, *userID, AppletResourceUserId };
|
||||
|
||||
u64 total_out=0;
|
||||
Result rc = serviceDispatchInOut(&g_capsuSrv, cmd_id, in, total_out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { entries, count*entrysize } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _capsuOpenAccessorSessionForApplication(Service* srv_out, const CapsApplicationAlbumFileEntry *entry) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsApplicationAlbumFileEntry entry;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *entry, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchIn(&g_capsuSrv, 60002, in,
|
||||
.in_send_pid = true,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuOpenAlbumMovieReadStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
|
||||
u64 AppletResourceUserId = 0;
|
||||
appletGetAppletResourceUserId(&AppletResourceUserId);
|
||||
|
||||
const struct {
|
||||
CapsApplicationAlbumFileEntry entry;
|
||||
u64 AppletResourceUserId;
|
||||
} in = { *entry, AppletResourceUserId };
|
||||
|
||||
return serviceDispatchInOut(&g_capsuAccessor, 2001, in, *stream,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _capsuGetAlbumMovieReadStreamMovieDataSize(u64 stream, u64 *size) {
|
||||
return serviceDispatchInOut(&g_capsuAccessor, 2003, stream, *size);
|
||||
}
|
||||
|
||||
static Result _capsuReadMovieDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
|
||||
const struct {
|
||||
u64 stream;
|
||||
s64 offset;
|
||||
} in = { stream, offset };
|
||||
|
||||
return serviceDispatchInOut(&g_capsuAccessor, 2004, in, *actual_size,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { buffer, size } },
|
||||
);
|
||||
}
|
||||
|
||||
static inline u64 _capsuMakeTimestamp(const CapsAlbumFileDateTime *datetime) {
|
||||
struct tm tmptm = {.tm_sec = datetime->second, .tm_min = datetime->minute, .tm_hour = datetime->hour,
|
||||
.tm_mday = datetime->day, .tm_mon = datetime->month, .tm_year = datetime->year - 1900};
|
||||
|
||||
return mktime(&tmptm);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
|
||||
u64 start_timestamp = 0x386BF200;
|
||||
u64 end_timestamp = 0xF4865700;
|
||||
|
||||
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
|
||||
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
|
||||
|
||||
if (hosversionBefore(6,0,0)) { // GetAlbumFileListDeprecated0
|
||||
if (start_datetime) start_timestamp = _capsuMakeTimestamp(start_datetime);
|
||||
if (end_datetime) end_timestamp = _capsuMakeTimestamp(end_datetime);
|
||||
return _capsuGetAlbumFileList0AafeAruidDeprecated(entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_timestamp, end_timestamp, total_entries);
|
||||
}
|
||||
|
||||
return _capsuGetAlbumFileListAaeAruid(140, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
|
||||
if (hosversionBefore(6,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
|
||||
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
|
||||
|
||||
return _capsuGetAlbumFileListAaeUidAruid(141, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
|
||||
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
|
||||
|
||||
return _capsuGetAlbumFileListAaeAruid(142, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
|
||||
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
|
||||
|
||||
return _capsuGetAlbumFileListAaeUidAruid(143, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
|
||||
}
|
||||
|
||||
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry) {
|
||||
return _capsuDeleteAlbumFileByAruid(103, type, entry);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
|
||||
return _capsuGetAlbumFileSizeByAruid(entry, size);
|
||||
}
|
||||
|
||||
static void _capsuProcessImageOutput(CapsLoadAlbumScreenShotImageOutputForApplication *out, s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size) {
|
||||
if (out==NULL) return;
|
||||
|
||||
if (width) *width = out->width;
|
||||
if (height) *height = out->height;
|
||||
if (attr) memcpy(attr, &out->attr, sizeof(out->attr));
|
||||
|
||||
if (userdata && userdata_maxsize) {
|
||||
memset(userdata, 0, userdata_maxsize);
|
||||
if (userdata_maxsize > sizeof(out->appdata.userdata)) userdata_maxsize = sizeof(out->appdata.userdata);
|
||||
if (userdata_maxsize > out->appdata.size) userdata_maxsize = out->appdata.size;
|
||||
memcpy(userdata, out->appdata.userdata, userdata_maxsize);
|
||||
}
|
||||
if (userdata_size) *userdata_size = out->appdata.size > sizeof(out->appdata.userdata) ? sizeof(out->appdata.userdata) : out->appdata.size;
|
||||
}
|
||||
|
||||
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
|
||||
Result rc=0;
|
||||
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
|
||||
|
||||
rc = _capsuLoadAlbumScreenShotImageByAruid(110, &out, image, image_size, workbuf, workbuf_size, entry, option);
|
||||
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
|
||||
Result rc=0;
|
||||
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
|
||||
|
||||
rc = _capsuLoadAlbumScreenShotImageByAruid(120, &out, image, image_size, workbuf, workbuf_size, entry, option);
|
||||
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk) {
|
||||
return _capsuPrecheckToCreateContentsByAruid(type, unk);
|
||||
}
|
||||
|
||||
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
|
||||
Result rc=0;
|
||||
|
||||
if (!serviceIsActive(&g_capsuAccessor)) rc =_capsuOpenAccessorSessionForApplication(&g_capsuAccessor, entry);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _capsuOpenAlbumMovieReadStream(stream, entry);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result capsuCloseAlbumMovieStream(u64 stream) {
|
||||
if (!serviceIsActive(&g_capsuAccessor))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _capsuCmdInU64NoOut(&g_capsuAccessor, stream, 2002);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size) {
|
||||
if (!serviceIsActive(&g_capsuAccessor))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _capsuGetAlbumMovieReadStreamMovieDataSize(stream, size);
|
||||
}
|
||||
|
||||
Result capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
|
||||
if (!serviceIsActive(&g_capsuAccessor))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _capsuReadMovieDataFromAlbumMovieReadStream(stream, offset, buffer, size, actual_size);
|
||||
}
|
||||
|
||||
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream) {
|
||||
if (!serviceIsActive(&g_capsuAccessor))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _capsuCmdInU64NoOut(&g_capsuAccessor, stream, 2005);
|
||||
}
|
||||
|
||||
@ -1,28 +1,17 @@
|
||||
// Copyright 2018 SciresM
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "services/csrng.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/spl.h"
|
||||
|
||||
static Service g_csrngSrv;
|
||||
static u64 g_csrngRefCnt;
|
||||
|
||||
Result csrngInitialize(void) {
|
||||
atomicIncrement64(&g_csrngRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_csrngSrv))
|
||||
return 0;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(csrng);
|
||||
|
||||
Result _csrngInitialize(void) {
|
||||
return smGetService(&g_csrngSrv, "csrng");
|
||||
}
|
||||
|
||||
void csrngExit(void) {
|
||||
if (atomicDecrement64(&g_csrngRefCnt) == 0)
|
||||
serviceClose(&g_csrngSrv);
|
||||
void _csrngCleanup(void) {
|
||||
serviceClose(&g_csrngSrv);
|
||||
}
|
||||
|
||||
Service* csrngGetServiceSession(void) {
|
||||
@ -30,34 +19,8 @@ Service* csrngGetServiceSession(void) {
|
||||
}
|
||||
|
||||
Result csrngGetRandomBytes(void *out, size_t out_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddRecvBuffer(&c, out, out_size, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_csrngSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatch(&g_csrngSrv, 0,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { out, out_size } },
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// Copyright 2017 plutoo
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "kernel/detect.h"
|
||||
#include "kernel/svc.h"
|
||||
#include "sf/service.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
@ -17,42 +18,30 @@ static void _fatalImpl(u32 cmd_id, Result err, FatalType type, FatalContext *ctx
|
||||
svcBreak(0x80000000, err, 0);
|
||||
}
|
||||
|
||||
if (!smHasInitialized()) {
|
||||
rc = smInitialize();
|
||||
Handle session;
|
||||
rc = smInitialize();
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = smGetServiceOriginal(&session, smEncodeName("fatal:u"));
|
||||
smExit();
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
Handle srv;
|
||||
rc = smGetServiceOriginal(&srv, smEncodeName("fatal:u"));
|
||||
const struct {
|
||||
u32 result;
|
||||
u32 type;
|
||||
u64 pid_placeholder;
|
||||
} in = { err, type };
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
if (ctx != NULL) {
|
||||
ipcAddSendBuffer(&c, ctx, sizeof(*ctx), BufferType_Normal);
|
||||
}
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 result;
|
||||
u32 type;
|
||||
u64 pid_placeholder;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->result = err;
|
||||
raw->type = type;
|
||||
raw->pid_placeholder = 0; // Overwritten by fatal with PID descriptor.
|
||||
|
||||
ipcDispatch(srv);
|
||||
}
|
||||
Service s;
|
||||
serviceCreate(&s, session);
|
||||
serviceDispatchIn(&s, cmd_id, in,
|
||||
.buffer_attrs = { ctx ? (SfBufferAttr_In | SfBufferAttr_HipcMapAlias) : 0U },
|
||||
.buffers = { { ctx, sizeof(*ctx) } },
|
||||
.in_send_pid = true,
|
||||
);
|
||||
serviceClose(&s);
|
||||
}
|
||||
|
||||
|
||||
switch (type) {
|
||||
case FatalType_ErrorReport:
|
||||
break;
|
||||
@ -72,7 +61,7 @@ void NORETURN fatalSimple(Result err) {
|
||||
}
|
||||
|
||||
void fatalWithType(Result err, FatalType type) {
|
||||
_fatalImpl(1, err, type, NULL);
|
||||
_fatalImpl(1, err, type, NULL);
|
||||
}
|
||||
|
||||
void fatalWithContext(Result err, FatalType type, FatalContext *ctx) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,32 @@
|
||||
// Copyright 2018 SciresM
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/fs.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/fsldr.h"
|
||||
|
||||
static Service g_fsldrSrv;
|
||||
static u64 g_fsldrRefCnt;
|
||||
|
||||
Result fsldrSetCurrentProcess(void);
|
||||
NX_GENERATE_SERVICE_GUARD(fsldr);
|
||||
|
||||
Result fsldrInitialize(void) {
|
||||
atomicIncrement64(&g_fsldrRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_fsldrSrv))
|
||||
return 0;
|
||||
NX_INLINE Result _fsldrSetCurrentProcess(void);
|
||||
|
||||
Result _fsldrInitialize(void) {
|
||||
Result rc = smGetService(&g_fsldrSrv, "fsp-ldr");
|
||||
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = serviceConvertToDomain(&g_fsldrSrv);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(4,0,0)) {
|
||||
rc = fsldrSetCurrentProcess();
|
||||
rc = _fsldrSetCurrentProcess();
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
void fsldrExit(void) {
|
||||
if (atomicDecrement64(&g_fsldrRefCnt) == 0)
|
||||
serviceClose(&g_fsldrSrv);
|
||||
void _fsldrCleanup(void) {
|
||||
serviceClose(&g_fsldrSrv);
|
||||
}
|
||||
|
||||
Service* fsldrGetServiceSession(void) {
|
||||
@ -44,115 +34,25 @@ Service* fsldrGetServiceSession(void) {
|
||||
}
|
||||
|
||||
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out) {
|
||||
char send_path[FS_MAX_PATH+1] = {0};
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 tid;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->tid = tid;
|
||||
|
||||
char send_path[FS_MAX_PATH + 1];
|
||||
strncpy(send_path, path, FS_MAX_PATH);
|
||||
Result rc = serviceIpcDispatch(&g_fsldrSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreateSubservice(&out->s, &g_fsldrSrv, &r, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_fsldrSrv, 0, tid,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_In,
|
||||
},
|
||||
.buffers = {
|
||||
{ send_path, FS_MAX_PATH },
|
||||
},
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s,
|
||||
);
|
||||
}
|
||||
|
||||
Result fsldrIsArchivedProgram(u64 pid, bool *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_fsldrSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 is_archived;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->is_archived != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(&g_fsldrSrv, 1, pid, *out);
|
||||
}
|
||||
|
||||
Result fsldrSetCurrentProcess(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 unk;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->unk = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_fsldrSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result _fsldrSetCurrentProcess(void) {
|
||||
u64 pid_placeholder = 0;
|
||||
return serviceDispatchIn(&g_fsldrSrv, 2, pid_placeholder, .in_send_pid = true);
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,10 @@
|
||||
#include "kernel/tmem.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/grc.h"
|
||||
#include "services/caps.h"
|
||||
#include "services/applet.h"
|
||||
#include "display/native_window.h"
|
||||
#include "audio/audio.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
static void _grcGameMovieTrimmerClose(GrcGameMovieTrimmer *t);
|
||||
@ -44,6 +47,114 @@ static Result _grcCmdNoIO(Service* srv, u64 cmd_id) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcCmdInU64(Service* srv, u64 inval, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 inval;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->inval = inval;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcCmdInU64Out32(Service* srv, u64 inval, u32 *out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 inval;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->inval = inval;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) *out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcCmdNoInOut64(Service* srv, u64 *out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) {
|
||||
*out = resp->out;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool autoclear) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
@ -80,6 +191,80 @@ static Result _grcGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool auto
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcCmdInU64OutEvent(Service* srv, u64 inval, Event* out_event, u64 cmd_id, bool autoclear) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 inval;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->inval = inval;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(out_event, r.Handles[0], autoclear);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcGetSession(Service* srv, Service* srv_out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreateSubservice(srv_out, srv, &r, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcCreateGameMovieTrimmer(GrcGameMovieTrimmer *t, size_t size) {
|
||||
Result rc=0;
|
||||
Result retryrc = MAKERESULT(212, 4);
|
||||
@ -260,6 +445,314 @@ Result grcTrimGameMovie(GrcGameMovieId *dst_movieid, const GrcGameMovieId *src_m
|
||||
return rc;
|
||||
}
|
||||
|
||||
// IMovieMaker
|
||||
|
||||
void grcCreateOffscreenRecordingParameter(GrcOffscreenRecordingParameter *param) {
|
||||
memset(param, 0, sizeof(*param));
|
||||
param->unk_x10 = 0x103;
|
||||
|
||||
param->video_bitrate = 8000000;
|
||||
param->video_width = 1280;
|
||||
param->video_height = 720;
|
||||
param->video_framerate = 30;
|
||||
param->video_keyFrameInterval = 30;
|
||||
|
||||
param->audio_bitrate = hosversionAtLeast(6,0,0) ? 128000 : 1536000;
|
||||
param->audio_samplerate = 48000;
|
||||
param->audio_channel_count = 2;
|
||||
param->audio_sample_format = PcmFormat_Int16;
|
||||
|
||||
param->video_imageOrientation = AlbumImageOrientation_Unknown0;
|
||||
}
|
||||
|
||||
Result grcCreateMovieMaker(GrcMovieMaker *m, size_t size) {
|
||||
Result rc=0;
|
||||
Result retryrc = MAKERESULT(212, 4);
|
||||
s32 binder_id=0;
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
rc = tmemCreate(&m->tmem, size, Perm_None);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = appletCreateMovieMaker(&m->a, &m->tmem);
|
||||
|
||||
while(rc == retryrc) {
|
||||
svcSleepThread(100000000);
|
||||
rc = appletCreateMovieMaker(&m->a, &m->tmem);
|
||||
}
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _grcGetSession(&m->a, &m->s, 0); // GetGrcMovieMaker
|
||||
|
||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _grcCmdInU64(&m->s, capsGetShimLibraryVersion(), 9); // SetAlbumShimLibraryVersion
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _grcCmdNoInOut64(&m->a, &m->layer_handle, 1); // GetLayerHandle
|
||||
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _grcGetSession(&m->s, &m->video_proxy, 2); // CreateVideoProxy
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64Out32(&m->s, m->layer_handle, (u32*)&binder_id, 10); // OpenOffscreenLayer
|
||||
if (R_SUCCEEDED(rc)) m->layer_open = true;
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = nwindowCreate(&m->win, &m->video_proxy, binder_id, false);
|
||||
if (R_SUCCEEDED(rc)) rc = nwindowSetDimensions(&m->win, 1280, 720);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64OutEvent(&m->s, m->layer_handle, &m->recording_event, 50, false); // GetOffscreenLayerRecordingFinishReadyEvent
|
||||
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64OutEvent(&m->s, m->layer_handle, &m->audio_event, 52, false); // GetOffscreenLayerAudioEncodeReadyEvent
|
||||
|
||||
if (R_FAILED(rc)) grcMovieMakerClose(m);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void grcMovieMakerClose(GrcMovieMaker *m) {
|
||||
grcMovieMakerAbort(m);
|
||||
|
||||
eventClose(&m->audio_event);
|
||||
eventClose(&m->recording_event);
|
||||
|
||||
nwindowClose(&m->win);
|
||||
if (m->layer_open) {
|
||||
_grcCmdInU64(&m->s, m->layer_handle, 11); // CloseOffscreenLayer
|
||||
m->layer_open = false;
|
||||
}
|
||||
|
||||
serviceClose(&m->video_proxy);
|
||||
serviceClose(&m->s);
|
||||
serviceClose(&m->a);
|
||||
tmemClose(&m->tmem);
|
||||
}
|
||||
|
||||
Result grcMovieMakerStart(GrcMovieMaker *m, const GrcOffscreenRecordingParameter *param) {
|
||||
if (!serviceIsActive(&m->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 layer_handle;
|
||||
GrcOffscreenRecordingParameter param;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 24;
|
||||
raw->layer_handle = m->layer_handle;
|
||||
memcpy(&raw->param, param, sizeof(GrcOffscreenRecordingParameter));
|
||||
|
||||
Result rc = serviceIpcDispatch(&m->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&m->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) m->started_flag = true;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result grcMovieMakerAbort(GrcMovieMaker *m) {
|
||||
Result rc=0;
|
||||
|
||||
if (!serviceIsActive(&m->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
if (!m->started_flag)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
rc = _grcCmdInU64(&m->s, m->layer_handle, 21); // AbortOffscreenRecording
|
||||
if (R_SUCCEEDED(rc)) m->started_flag = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcMovieMakerCompleteOffscreenRecordingFinishEx0(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, userdata, userdata_size, BufferType_Normal);
|
||||
ipcAddSendBuffer(&c, thumbnail, thumbnail_size, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
s32 width;
|
||||
s32 height;
|
||||
u64 layer_handle;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 25;
|
||||
raw->width = width;
|
||||
raw->height = height;
|
||||
raw->layer_handle = m->layer_handle;
|
||||
|
||||
Result rc = serviceIpcDispatch(&m->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
CapsApplicationAlbumEntry entry;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&m->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _grcMovieMakerCompleteOffscreenRecordingFinishEx1(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry) {
|
||||
if (hosversionBefore(7,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, userdata, userdata_size, BufferType_Normal);
|
||||
ipcAddSendBuffer(&c, thumbnail, thumbnail_size, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
s32 width;
|
||||
s32 height;
|
||||
u64 layer_handle;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 26;
|
||||
raw->width = width;
|
||||
raw->height = height;
|
||||
raw->layer_handle = m->layer_handle;
|
||||
|
||||
Result rc = serviceIpcDispatch(&m->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
CapsApplicationAlbumEntry entry;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&m->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && entry) *entry = resp->entry;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result grcMovieMakerFinish(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry) {
|
||||
Result rc=0;
|
||||
|
||||
if (!serviceIsActive(&m->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
if (hosversionBefore(7,0,0) && entry)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
rc = _grcCmdInU64(&m->s, m->layer_handle, 22); // RequestOffscreenRecordingFinishReady
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = eventWait(&m->recording_event, U64_MAX);
|
||||
|
||||
if (hosversionAtLeast(7,0,0))
|
||||
rc = _grcMovieMakerCompleteOffscreenRecordingFinishEx1(m, width, height, userdata, userdata_size, thumbnail, thumbnail_size, entry);
|
||||
else
|
||||
rc = _grcMovieMakerCompleteOffscreenRecordingFinishEx0(m, width, height, userdata, userdata_size, thumbnail, thumbnail_size);
|
||||
|
||||
if (R_FAILED(rc)) grcMovieMakerAbort(m);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result grcMovieMakerGetError(GrcMovieMaker *m) {
|
||||
if (!serviceIsActive(&m->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _grcCmdInU64(&m->s, m->layer_handle, 30); // GetOffscreenLayerError
|
||||
}
|
||||
|
||||
static Result _grcMovieMakerEncodeOffscreenLayerAudioSample(GrcMovieMaker *m, const void* buffer, size_t size, u64 *out_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, buffer, size, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 layer_handle;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 41;
|
||||
raw->layer_handle = m->layer_handle;
|
||||
|
||||
Result rc = serviceIpcDispatch(&m->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 out_size;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&m->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_size) *out_size = resp->out_size;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result grcMovieMakerEncodeAudioSample(GrcMovieMaker *m, const void* buffer, size_t size) {
|
||||
Result rc=0;
|
||||
u64 out_size=0;
|
||||
u8 *bufptr = (u8*)buffer;
|
||||
|
||||
if (!serviceIsActive(&m->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
for (u64 pos=0; size!=0; pos+=out_size, size-=out_size) {
|
||||
rc = eventWait(&m->audio_event, U64_MAX);
|
||||
if (R_FAILED(rc)) break;
|
||||
|
||||
rc = _grcMovieMakerEncodeOffscreenLayerAudioSample(m, &bufptr[pos], size, &out_size);
|
||||
if (R_FAILED(rc)) break;
|
||||
if (out_size > size) out_size = size;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// grc:d
|
||||
|
||||
static Service g_grcdSrv;
|
||||
|
||||
@ -97,7 +97,7 @@ Result hidInitialize(void)
|
||||
rc = _hidActivateNpad();
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = hidSetSupportedNpadStyleSet(TYPE_PROCONTROLLER | TYPE_HANDHELD | TYPE_JOYCON_PAIR | TYPE_JOYCON_LEFT | TYPE_JOYCON_RIGHT);
|
||||
rc = hidSetSupportedNpadStyleSet(TYPE_PROCONTROLLER | TYPE_HANDHELD | TYPE_JOYCON_PAIR | TYPE_JOYCON_LEFT | TYPE_JOYCON_RIGHT | TYPE_SYSTEM_EXT | TYPE_SYSTEM);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = hidSetSupportedNpadIdType(idbuf, 9);
|
||||
@ -1032,11 +1032,11 @@ Result hidSetNpadJoyHoldType(HidJoyHoldType type) {
|
||||
}
|
||||
|
||||
Result hidSetNpadJoyAssignmentModeSingleByDefault(HidControllerID id) {
|
||||
return _hidCmdWithInputU32(122, id);
|
||||
return _hidCmdWithInputU32(122, hidControllerIDToOfficial(id));
|
||||
}
|
||||
|
||||
Result hidSetNpadJoyAssignmentModeDual(HidControllerID id) {
|
||||
return _hidCmdWithInputU32(124, id);
|
||||
return _hidCmdWithInputU32(124, hidControllerIDToOfficial(id));
|
||||
}
|
||||
|
||||
Result hidMergeSingleJoyAsDualJoy(HidControllerID id0, HidControllerID id1) {
|
||||
@ -1063,8 +1063,8 @@ Result hidMergeSingleJoyAsDualJoy(HidControllerID id0, HidControllerID id1) {
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 125;
|
||||
raw->id0 = id0;
|
||||
raw->id1 = id1;
|
||||
raw->id0 = hidControllerIDToOfficial(id0);
|
||||
raw->id1 = hidControllerIDToOfficial(id1);
|
||||
raw->AppletResourceUserId = AppletResourceUserId;
|
||||
|
||||
rc = serviceIpcDispatch(&g_hidSrv);
|
||||
@ -1739,3 +1739,44 @@ Result hidResetSevenSixAxisSensorTimestamp(void) {
|
||||
return _hidCmdWithNoInput(310);
|
||||
}
|
||||
|
||||
Result hidGetNpadInterfaceType(HidControllerID id, u8 *out) {
|
||||
if (hosversionBefore(4,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 405;
|
||||
raw->id = hidControllerIDToOfficial(id);
|
||||
|
||||
rc = serviceIpcDispatch(&g_hidSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) *out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -11,11 +11,35 @@
|
||||
|
||||
static Service g_hiddbgSrv;
|
||||
static u64 g_hiddbgRefCnt;
|
||||
static size_t g_hiddbgPtrbufsize;
|
||||
|
||||
static bool g_hiddbgHdlsInitialized;
|
||||
static TransferMemory g_hiddbgHdlsTmem;
|
||||
|
||||
static const u32 g_hiddbgDeviceTypeInternalTable[] = {
|
||||
BIT(20), // DeviceType 0 Invalid
|
||||
BIT(0*4+2), // DeviceType 1 JoyRight
|
||||
BIT(0*4+1), // DeviceType 2 JoyLeft
|
||||
BIT(1*4+0), // DeviceType 3 FullKey
|
||||
BIT(1*4+1), // DeviceType 4 JoyLeft
|
||||
BIT(1*4+2), // DeviceType 5 JoyRight
|
||||
BIT(8), // DeviceType 6 FullKey
|
||||
BIT(11), // DeviceType 7 LarkLeft (HVC)
|
||||
BIT(12), // DeviceType 8 LarkRight (HVC)
|
||||
BIT(13), // DeviceType 9 LarkLeft (NES)
|
||||
BIT(14), // DeviceType 10 LarkRight (NES)
|
||||
BIT(15), // DeviceType 11 Invalid
|
||||
BIT(16), // DeviceType 12 Palma (Invalid for DeviceTypeInternal)
|
||||
BIT(9), // DeviceType 13 FullKey
|
||||
BIT(20), // DeviceType 14 Invalid
|
||||
BIT(10), // DeviceType 15 FullKey
|
||||
BIT(18), // DeviceType 16 Invalid
|
||||
BIT(19), // DeviceType 17 Invalid
|
||||
BIT(20), // DeviceType 18 Invalid
|
||||
BIT(21), // DeviceType 19 ::HidDeviceTypeBits_System with HidControllerType |= TYPE_PROCONTROLLER.
|
||||
BIT(22), // DeviceType 20 ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
|
||||
BIT(23), // DeviceType 21 ::HidDeviceType System with HidControllerType |= TYPE_JOYCON_PAIR.
|
||||
};
|
||||
|
||||
Result hiddbgInitialize(void) {
|
||||
atomicIncrement64(&g_hiddbgRefCnt);
|
||||
|
||||
@ -24,8 +48,6 @@ Result hiddbgInitialize(void) {
|
||||
|
||||
Result rc = smGetService(&g_hiddbgSrv, "hid:dbg");
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_hiddbgSrv.handle, &g_hiddbgPtrbufsize);
|
||||
|
||||
if (R_FAILED(rc)) hiddbgExit();
|
||||
|
||||
return rc;
|
||||
@ -292,8 +314,55 @@ Result hiddbgReadSerialFlash(u32 offset, void* buffer, size_t size, u64 UniquePa
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result hiddbgGetUniquePadDeviceTypeSetInternal(u64 UniquePadId, u32 *out) {
|
||||
if (hosversionBefore(6,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 UniquePadId;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 234;
|
||||
raw->UniquePadId = UniquePadId;
|
||||
|
||||
rc = serviceIpcDispatch(&g_hiddbgSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) { //Pre-9.0.0 output is an u32, with [9.0.0+] it's an u8.
|
||||
if (hosversionBefore(9,0,0))
|
||||
*out = resp->out;
|
||||
else
|
||||
*out = resp->out & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
@ -326,6 +395,8 @@ Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
|
||||
}
|
||||
|
||||
@ -333,7 +404,7 @@ Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *
|
||||
}
|
||||
|
||||
Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
@ -366,6 +437,8 @@ Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadS
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && state) memcpy(state, &resp->state, sizeof(*state));
|
||||
}
|
||||
|
||||
@ -373,7 +446,7 @@ Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadS
|
||||
}
|
||||
|
||||
Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
@ -387,7 +460,7 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
|
||||
} *raw;
|
||||
|
||||
ipcAddRecvStatic(&c, AbstractedPadHandles, sizeof(u64)*count, 0);
|
||||
ipcAddRecvSmart(&c, g_hiddbgPtrbufsize, states, sizeof(HiddbgAbstractedPadState)*count, 0);
|
||||
ipcAddRecvSmart(&c, g_hiddbgSrv.pointer_buffer_size, states, sizeof(HiddbgAbstractedPadState)*count, 0);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
||||
|
||||
@ -407,6 +480,8 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
|
||||
}
|
||||
|
||||
@ -414,7 +489,7 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
|
||||
}
|
||||
|
||||
Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
@ -448,13 +523,15 @@ Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const Hiddbg
|
||||
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId) {
|
||||
if (hosversionBefore(5,0,0))
|
||||
if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
Result rc;
|
||||
@ -485,6 +562,8 @@ Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId) {
|
||||
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -497,6 +576,84 @@ Result hiddbgUnsetAllAutoPilotVirtualPadState(void) {
|
||||
return _hiddbgCmdNoIO(323);
|
||||
}
|
||||
|
||||
static u32 _hiddbgConvertDeviceTypeToDeviceTypeInternal(u8 deviceType) {
|
||||
if (deviceType >= sizeof(g_hiddbgDeviceTypeInternalTable)/sizeof(u32)) return g_hiddbgDeviceTypeInternalTable[0];
|
||||
return g_hiddbgDeviceTypeInternalTable[deviceType];
|
||||
}
|
||||
|
||||
static u8 _hiddbgConvertDeviceTypeInternalToDeviceType(u32 deviceType) {
|
||||
for (u32 i=0; i<sizeof(g_hiddbgDeviceTypeInternalTable)/sizeof(u32); i++) {
|
||||
if (deviceType == g_hiddbgDeviceTypeInternalTable[i]) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _hiddbgConvertHdlsDeviceInfoToV7(HiddbgHdlsDeviceInfoV7 *out, const HiddbgHdlsDeviceInfo *in) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
out->deviceTypeInternal = _hiddbgConvertDeviceTypeToDeviceTypeInternal(in->deviceType);
|
||||
out->singleColorBody = in->singleColorBody;
|
||||
out->singleColorButtons = in->singleColorButtons;
|
||||
out->npadInterfaceType = in->npadInterfaceType;
|
||||
}
|
||||
|
||||
static void _hiddbgConvertHdlsDeviceInfoFromV7(HiddbgHdlsDeviceInfo *out, const HiddbgHdlsDeviceInfoV7 *in) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
out->deviceType = _hiddbgConvertDeviceTypeInternalToDeviceType(in->deviceTypeInternal);
|
||||
out->npadInterfaceType = in->npadInterfaceType;
|
||||
out->singleColorBody = in->singleColorBody;
|
||||
out->singleColorButtons = in->singleColorButtons;
|
||||
//Leave out color*Grip at zero since V7 doesn't have those.
|
||||
}
|
||||
|
||||
static void _hiddbgConverHiddbgHdlsStateToV7(HiddbgHdlsStateV7 *out, const HiddbgHdlsState *in) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
out->powerConnected = (in->flags & BIT(0)) != 0;
|
||||
out->flags = (in->flags & BIT(1)) != 0;
|
||||
out->batteryCharge = in->batteryCharge;
|
||||
out->buttons = in->buttons;
|
||||
memcpy(out->joysticks, in->joysticks, sizeof(in->joysticks));
|
||||
out->unk_x20 = in->unk_x20;
|
||||
}
|
||||
|
||||
static void _hiddbgConverHiddbgHdlsStateFromV7(HiddbgHdlsState *out, const HiddbgHdlsStateV7 *in) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
out->batteryCharge = in->batteryCharge;
|
||||
out->flags = (in->powerConnected & 1) | ((in->flags & 1)<<1);
|
||||
out->buttons = in->buttons;
|
||||
memcpy(out->joysticks, in->joysticks, sizeof(in->joysticks));
|
||||
out->unk_x20 = in->unk_x20;
|
||||
}
|
||||
|
||||
static void _hiddbgConvertHdlsStateListToV7(HiddbgHdlsStateListV7 *out, const HiddbgHdlsStateList *in) {
|
||||
s32 count;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->total_entries = in->total_entries;
|
||||
count = out->total_entries > 0x10 ? 0x10 : out->total_entries;
|
||||
|
||||
for (s32 i=0; i<count; i++) {
|
||||
out->entries[i].HdlsHandle = in->entries[i].HdlsHandle;
|
||||
_hiddbgConvertHdlsDeviceInfoToV7(&out->entries[i].device, &in->entries[i].device);
|
||||
_hiddbgConverHiddbgHdlsStateToV7(&out->entries[i].state, &in->entries[i].state);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hiddbgConvertHdlsStateListFromV7(HiddbgHdlsStateList *out, const HiddbgHdlsStateListV7 *in) {
|
||||
s32 count;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->total_entries = in->total_entries;
|
||||
count = out->total_entries > 0x10 ? 0x10 : out->total_entries;
|
||||
|
||||
for (s32 i=0; i<count; i++) {
|
||||
out->entries[i].HdlsHandle = in->entries[i].HdlsHandle;
|
||||
_hiddbgConvertHdlsDeviceInfoFromV7(&out->entries[i].device, &in->entries[i].device);
|
||||
_hiddbgConverHiddbgHdlsStateFromV7(&out->entries[i].state, &in->entries[i].state);
|
||||
}
|
||||
}
|
||||
|
||||
static Result _hiddbgAttachHdlsWorkBuffer(TransferMemory *tmem) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
@ -594,7 +751,15 @@ Result hiddbgDumpHdlsStates(HiddbgHdlsStateList *state) {
|
||||
|
||||
rc = _hiddbgCmdNoIO(327);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
if (state) memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state));
|
||||
if (state) {
|
||||
if (hosversionBefore(9,0,0)) {
|
||||
HiddbgHdlsStateListV7 statev7;
|
||||
memcpy(&statev7, g_hiddbgHdlsTmem.src_addr, sizeof(statev7));
|
||||
_hiddbgConvertHdlsStateListFromV7(state, &statev7);
|
||||
}
|
||||
else
|
||||
memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -622,10 +787,54 @@ Result hiddbgApplyHdlsStateList(const HiddbgHdlsStateList *state) {
|
||||
if (state==NULL)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state));
|
||||
if (hosversionBefore(9,0,0)) {
|
||||
HiddbgHdlsStateListV7 statev7;
|
||||
_hiddbgConvertHdlsStateListToV7(&statev7, state);
|
||||
memcpy(g_hiddbgHdlsTmem.src_addr, &statev7, sizeof(statev7));
|
||||
}
|
||||
else
|
||||
memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state));
|
||||
|
||||
return _hiddbgCmdNoIO(329);
|
||||
}
|
||||
|
||||
static Result _hiddbgAttachHdlsVirtualDeviceV7(u64 *HdlsHandle, const HiddbgHdlsDeviceInfoV7 *info) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
HiddbgHdlsDeviceInfoV7 info;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 330;
|
||||
raw->info = *info;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_hiddbgSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 handle;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && HdlsHandle) *HdlsHandle = resp->handle;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
@ -670,7 +879,13 @@ Result hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo
|
||||
if (!g_hiddbgHdlsInitialized)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _hiddbgAttachHdlsVirtualDevice(HdlsHandle, info);
|
||||
if (hosversionBefore(9,0,0)) {
|
||||
HiddbgHdlsDeviceInfoV7 infov7;
|
||||
_hiddbgConvertHdlsDeviceInfoToV7(&infov7, info);
|
||||
return _hiddbgAttachHdlsVirtualDeviceV7(HdlsHandle, &infov7);
|
||||
}
|
||||
else
|
||||
return _hiddbgAttachHdlsVirtualDevice(HdlsHandle, info);
|
||||
}
|
||||
|
||||
Result hiddbgDetachHdlsVirtualDevice(u64 HdlsHandle) {
|
||||
@ -690,16 +905,30 @@ static Result _hiddbgSetHdlsState(u64 HdlsHandle, const HiddbgHdlsState *state)
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
HiddbgHdlsState state;
|
||||
u64 handle;
|
||||
union {
|
||||
struct {
|
||||
HiddbgHdlsStateV7 state;
|
||||
u64 handle;
|
||||
} v7; // [7.0.0-8.1.0]
|
||||
struct {
|
||||
u64 handle;
|
||||
HiddbgHdlsState state;
|
||||
} v9; // [9.0.0+]
|
||||
};
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 332;
|
||||
memcpy(&raw->state, state, sizeof(*state));
|
||||
raw->handle = HdlsHandle;
|
||||
if (hosversionBefore(9,0,0)) {
|
||||
_hiddbgConverHiddbgHdlsStateToV7(&raw->v7.state, state);
|
||||
raw->v7.handle = HdlsHandle;
|
||||
}
|
||||
else {
|
||||
raw->v9.handle = HdlsHandle;
|
||||
memcpy(&raw->v9.state, state, sizeof(*state));
|
||||
}
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_hiddbgSrv);
|
||||
|
||||
|
||||
@ -6,20 +6,17 @@
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_i2cSrv;
|
||||
static size_t g_i2cSrvPtrBufSize;
|
||||
static u64 g_refCnt;
|
||||
|
||||
Result i2cInitialize(void) {
|
||||
Result rc = 0;
|
||||
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_i2cSrv))
|
||||
return 0;
|
||||
|
||||
rc = smGetService(&g_i2cSrv, "i2c");
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_i2cSrv.handle, &g_i2cSrvPtrBufSize);
|
||||
|
||||
if (R_FAILED(rc)) i2cExit();
|
||||
|
||||
@ -28,7 +25,6 @@ Result i2cInitialize(void) {
|
||||
|
||||
void i2cExit(void) {
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
g_i2cSrvPtrBufSize = 0;
|
||||
serviceClose(&g_i2cSrv);
|
||||
}
|
||||
}
|
||||
@ -78,7 +74,7 @@ Result i2cOpenSession(I2cSession *out, I2cDevice dev) {
|
||||
Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransactionOption option) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0);
|
||||
ipcAddSendSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -113,7 +109,7 @@ Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransa
|
||||
Result i2csessionReceiveAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0);
|
||||
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
@ -149,7 +145,7 @@ Result i2csessionExecuteCommandList(I2cSession *s, void *dst, size_t dst_size, c
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, cmd_list, cmd_list_size, 0);
|
||||
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, dst, dst_size, 0);
|
||||
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, dst, dst_size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
|
||||
@ -7,17 +7,18 @@
|
||||
#include "services/lr.h"
|
||||
#include "services/fs.h"
|
||||
#include "services/sm.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
static Service g_managerSrv;
|
||||
static u64 g_managerRefCnt;
|
||||
|
||||
Result lrInitialize(void) {
|
||||
atomicIncrement64(&g_managerRefCnt);
|
||||
|
||||
|
||||
if (serviceIsActive(&g_managerSrv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return smGetService(&g_managerSrv, "lr");
|
||||
}
|
||||
|
||||
@ -34,19 +35,19 @@ Service* lrGetServiceSession(void) {
|
||||
Result lrOpenLocationResolver(FsStorageId storage, LrLocationResolver* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 storage_id; // Actually u8
|
||||
} *raw;
|
||||
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->storage_id = (u32)storage;
|
||||
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_managerSrv);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -63,24 +64,24 @@ Result lrOpenLocationResolver(FsStorageId storage, LrLocationResolver* out) {
|
||||
serviceCreate(&out->s, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result lrOpenRegisteredLocationResolver(LrRegisteredLocationResolver* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_managerSrv);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -97,11 +98,11 @@ Result lrOpenRegisteredLocationResolver(LrRegisteredLocationResolver* out) {
|
||||
serviceCreate(&out->s, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
All the LocationResolver/RegisteredLocationResolver "Resolve" commands have a common API.
|
||||
This is a helper function to perform the work for those funcs, given a command ID.
|
||||
*/
|
||||
@ -110,18 +111,18 @@ static Result _lrResolvePath(Service* s, u64 cmd_id, u64 tid, char *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvStatic(&c, out_path, FS_MAX_PATH, 0);
|
||||
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 tid;
|
||||
} *raw;
|
||||
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->tid = tid;
|
||||
|
||||
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
@ -139,11 +140,11 @@ static Result _lrResolvePath(Service* s, u64 cmd_id, u64 tid, char *out) {
|
||||
strncpy(out, out_path, FS_MAX_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
All the LocationResolver/RegisteredLocationResolver "Redirect" commands have a common API.
|
||||
This is a helper function to perform the work for those funcs, given a command ID.
|
||||
*/
|
||||
@ -152,18 +153,18 @@ static Result _lrRedirectPath(Service* s, u64 cmd_id, u64 tid, const char *path)
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
|
||||
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 tid;
|
||||
} *raw;
|
||||
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->tid = tid;
|
||||
|
||||
|
||||
strncpy(send_path, path, FS_MAX_PATH);
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
|
||||
@ -178,10 +179,55 @@ static Result _lrRedirectPath(Service* s, u64 cmd_id, u64 tid, const char *path)
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
In 9.0.0, "RedirectApplication" commands began taking in a second tid argument.
|
||||
This is a helper function to perform the work for those funcs, given a command ID.
|
||||
*/
|
||||
static Result _lrRedirectApplicationPath(Service* s, u64 cmd_id, u64 tid, u64 tid2, const char *path) {
|
||||
// On < 9.0.0, call the original redirection helper.
|
||||
if (hosversionBefore(9,0,0)) {
|
||||
return _lrRedirectPath(s, cmd_id, tid, path);
|
||||
}
|
||||
|
||||
char send_path[FS_MAX_PATH+1] = {0};
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 tid;
|
||||
u64 tid2;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->tid = tid;
|
||||
raw->tid2 = tid2;
|
||||
|
||||
strncpy(send_path, path, FS_MAX_PATH);
|
||||
Result rc = serviceIpcDispatch(s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result lrLrResolveProgramPath(LrLocationResolver* lr, u64 tid, char *out) {
|
||||
return _lrResolvePath(&lr->s, 0, tid, out);
|
||||
@ -203,36 +249,36 @@ Result lrLrResolveDataPath(LrLocationResolver* lr, u64 tid, char *out) {
|
||||
return _lrResolvePath(&lr->s, 4, tid, out);
|
||||
}
|
||||
|
||||
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, const char *path) {
|
||||
return _lrRedirectPath(&lr->s, 5, tid, path);
|
||||
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
|
||||
return _lrRedirectApplicationPath(&lr->s, 5, tid, tid2, path);
|
||||
}
|
||||
|
||||
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, const char *path) {
|
||||
return _lrRedirectPath(&lr->s, 6, tid, path);
|
||||
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
|
||||
return _lrRedirectApplicationPath(&lr->s, 6, tid, tid2, path);
|
||||
}
|
||||
|
||||
Result lrLrResolveLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out) {
|
||||
Result lrLrResolveApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out) {
|
||||
return _lrResolvePath(&lr->s, 7, tid, out);
|
||||
}
|
||||
|
||||
Result lrLrRedirectLegalInformationPath(LrLocationResolver* lr, u64 tid, const char *path) {
|
||||
return _lrRedirectPath(&lr->s, 8, tid, path);
|
||||
Result lrLrRedirectApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
|
||||
return _lrRedirectApplicationPath(&lr->s, 8, tid, tid2, path);
|
||||
}
|
||||
|
||||
Result lrLrRefresh(LrLocationResolver* lr) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 9;
|
||||
|
||||
|
||||
Result rc = serviceIpcDispatch(&lr->s);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -245,7 +291,7 @@ Result lrLrRefresh(LrLocationResolver* lr) {
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,22 @@
|
||||
/**
|
||||
* @file nifm.c
|
||||
* @brief Network interface service IPC wrapper.
|
||||
* @author shadowninja108, shibboleet
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#include "service_guard.h"
|
||||
#include "services/nifm.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
static NifmServiceType g_nifmServiceType = NifmServiceType_NotInitialized;
|
||||
|
||||
static Service g_nifmSrv;
|
||||
static Service g_nifmIGS;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static Result _nifmCreateGeneralService(Service* out, u64 in);
|
||||
static Result _nifmCreateGeneralServiceOld(Service* out);
|
||||
static Result _nifmCreateGeneralService(Service* srv_out);
|
||||
static Result _nifmCreateGeneralServiceOld(Service* srv_out);
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(nifm);
|
||||
|
||||
void nifmSetServiceType(NifmServiceType serviceType) {
|
||||
g_nifmServiceType = serviceType;
|
||||
}
|
||||
|
||||
Result nifmInitialize(void) {
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_nifmSrv))
|
||||
return 0;
|
||||
|
||||
Result _nifmInitialize(void) {
|
||||
Result rc = 0;
|
||||
switch (g_nifmServiceType) {
|
||||
case NifmServiceType_NotInitialized:
|
||||
@ -47,393 +36,125 @@ Result nifmInitialize(void) {
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (hosversionAtLeast(3,0,0))
|
||||
rc = _nifmCreateGeneralService(&g_nifmIGS, 0); // What does this parameter do?
|
||||
rc = _nifmCreateGeneralService(&g_nifmIGS);
|
||||
else
|
||||
rc = _nifmCreateGeneralServiceOld(&g_nifmIGS);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc))
|
||||
nifmExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void nifmExit(void) {
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_nifmIGS);
|
||||
serviceClose(&g_nifmSrv);
|
||||
g_nifmServiceType = NifmServiceType_NotInitialized;
|
||||
}
|
||||
void _nifmCleanup(void) {
|
||||
serviceClose(&g_nifmIGS);
|
||||
serviceClose(&g_nifmSrv);
|
||||
g_nifmServiceType = NifmServiceType_NotInitialized;
|
||||
}
|
||||
|
||||
Service* nifmGetServiceSession_StaticService(void) {
|
||||
return &g_nifmSrv;
|
||||
}
|
||||
|
||||
Service* nifmGetServiceSession_GeneralService(void) {
|
||||
return &g_nifmIGS;
|
||||
}
|
||||
|
||||
static Result _nifmCmdNoIO(Service* srv, u32 cmd_id) {
|
||||
serviceAssumeDomain(srv);
|
||||
return serviceDispatch(srv, cmd_id);
|
||||
}
|
||||
|
||||
static Result _nifmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
|
||||
serviceAssumeDomain(srv);
|
||||
return serviceDispatch(srv, cmd_id,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _nifmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
serviceAssumeDomain(srv);
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _nifmCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) {
|
||||
serviceAssumeDomain(srv);
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _nifmCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
|
||||
u8 tmp=0;
|
||||
Result rc = _nifmCmdNoInOutU8(srv, &tmp, cmd_id);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp!=0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _nifmCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
|
||||
serviceAssumeDomain(srv);
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result _nifmCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
|
||||
return _nifmCmdInU8NoOut(srv, inval!=0, cmd_id);
|
||||
}
|
||||
|
||||
static Result _nifmCreateGeneralServiceOld(Service* srv_out) {
|
||||
return _nifmCmdGetSession(&g_nifmSrv, srv_out, 4);
|
||||
}
|
||||
|
||||
static Result _nifmCreateGeneralService(Service* srv_out) {
|
||||
u64 reserved=0;
|
||||
serviceAssumeDomain(&g_nifmSrv);
|
||||
return serviceDispatchIn(&g_nifmSrv, 5, reserved,
|
||||
.in_send_pid = true,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
Result nifmGetCurrentIpAddress(u32* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
*out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nifmIsWirelessCommunicationEnabled(bool* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 17;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out)
|
||||
*out = resp->out != 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _nifmCmdNoInOutU32(&g_nifmIGS, out, 12);
|
||||
}
|
||||
|
||||
Result nifmSetWirelessCommunicationEnabled(bool enable) {
|
||||
if (g_nifmServiceType < NifmServiceType_System)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
return _nifmCmdInBoolNoOut(&g_nifmIGS, enable, 16);
|
||||
}
|
||||
|
||||
Result nifmIsWirelessCommunicationEnabled(bool* out) {
|
||||
return _nifmCmdNoInOutBool(&g_nifmIGS, out, 17);
|
||||
}
|
||||
|
||||
Result nifmGetInternetConnectionStatus(NifmInternetConnectionType* connectionType, u32* wifiStrength, NifmInternetConnectionStatus* connectionStatus) {
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u8 value;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 16;
|
||||
raw->value = enable!= 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
u8 out1;
|
||||
u8 out2;
|
||||
u8 out3;
|
||||
} out;
|
||||
|
||||
serviceAssumeDomain(&g_nifmIGS);
|
||||
Result rc = serviceDispatchOut(&g_nifmIGS, 18, out);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (connectionType) *connectionType = out.out1;
|
||||
if (wifiStrength) *wifiStrength = out.out2;
|
||||
if (connectionStatus) *connectionStatus = out.out3;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nifmIsEthernetCommunicationEnabled(bool* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 20;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out)
|
||||
*out = resp->out != 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _nifmCmdNoInOutBool(&g_nifmIGS, out, 20);
|
||||
}
|
||||
|
||||
Result nifmIsAnyForegroundRequestAccepted(bool* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 22;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out)
|
||||
*out = resp->out != 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _nifmCmdNoInOutBool(&g_nifmIGS, out, 22);
|
||||
}
|
||||
|
||||
Result nifmPutToSleep(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 23;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _nifmCmdNoIO(&g_nifmIGS, 23);
|
||||
}
|
||||
|
||||
Result nifmWakeUp(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 24;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nifmGetInternetConnectionStatus(NifmInternetConnectionType* connectionType, u32* wifiStrength, NifmInternetConnectionStatus* connectionStatus)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 18;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmIGS);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out1;
|
||||
u8 out2;
|
||||
u8 out3;
|
||||
} PACKED *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (connectionType)
|
||||
*connectionType = resp->out1;
|
||||
|
||||
if (wifiStrength)
|
||||
*wifiStrength = resp->out2;
|
||||
|
||||
if (connectionStatus)
|
||||
*connectionStatus = resp->out3;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _nifmCreateGeneralService(Service* out, u64 in) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 param;
|
||||
} PACKED *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
raw->param = in;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
serviceCreateSubservice(out, &g_nifmSrv, &r, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _nifmCreateGeneralServiceOld(Service* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} PACKED *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_nifmSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nifmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_nifmSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
serviceCreateSubservice(out, &g_nifmSrv, &r, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _nifmCmdNoIO(&g_nifmIGS, 24);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,26 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "service_guard.h"
|
||||
#include "kernel/tmem.h"
|
||||
#include "services/applet.h"
|
||||
#include "nvidia/ioctl.h"
|
||||
#include "services/nv.h"
|
||||
#include "services/sm.h"
|
||||
#include "nvidia/ioctl.h"
|
||||
|
||||
__attribute__((weak)) u32 __nx_nv_transfermem_size = 0x800000;
|
||||
|
||||
static Service g_nvSrv;
|
||||
static Service g_nvSrvClone;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static size_t g_nvIpcBufferSize = 0;
|
||||
static TransferMemory g_nvTransfermem;
|
||||
|
||||
static Result _nvInitialize(Handle proc, Handle sharedmem, u32 transfermem_size);
|
||||
static Result _nvCmdInitialize(Handle proc, Handle sharedmem, u32 transfermem_size);
|
||||
static Result _nvSetClientPID(u64 AppletResourceUserId);
|
||||
|
||||
Result nvInitialize(void)
|
||||
NX_GENERATE_SERVICE_GUARD(nv);
|
||||
|
||||
Result _nvInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_nvSrv))
|
||||
return 0;
|
||||
|
||||
Result rc = 0;
|
||||
u64 AppletResourceUserId = 0;
|
||||
|
||||
@ -51,22 +44,17 @@ Result nvInitialize(void)
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
g_nvIpcBufferSize = 0;
|
||||
rc = ipcQueryPointerBufferSize(g_nvSrv.handle, &g_nvIpcBufferSize);
|
||||
g_nvIpcBufferSize = g_nvSrv.pointer_buffer_size;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = tmemCreate(&g_nvTransfermem, __nx_nv_transfermem_size, Perm_None);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _nvInitialize(CUR_PROCESS_HANDLE, g_nvTransfermem.handle, __nx_nv_transfermem_size);
|
||||
rc = _nvCmdInitialize(CUR_PROCESS_HANDLE, g_nvTransfermem.handle, __nx_nv_transfermem_size);
|
||||
|
||||
// Clone the session handle - the cloned session is used to execute certain commands in parallel
|
||||
Handle nv_clone = INVALID_HANDLE;
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = ipcCloneSession(g_nvSrv.handle, 1, &nv_clone);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
serviceCreate(&g_nvSrvClone, nv_clone);
|
||||
rc = serviceCloneEx(&g_nvSrv, 1, &g_nvSrvClone);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
@ -84,120 +72,43 @@ Result nvInitialize(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void nvExit(void)
|
||||
void _nvCleanup(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_nvSrvClone);
|
||||
serviceClose(&g_nvSrv);
|
||||
tmemClose(&g_nvTransfermem);
|
||||
}
|
||||
serviceClose(&g_nvSrvClone);
|
||||
serviceClose(&g_nvSrv);
|
||||
tmemClose(&g_nvTransfermem);
|
||||
}
|
||||
|
||||
static Result _nvInitialize(Handle proc, Handle sharedmem, u32 transfermem_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 transfermem_size;
|
||||
} *raw;
|
||||
|
||||
ipcSendHandleCopy(&c, proc);
|
||||
ipcSendHandleCopy(&c, sharedmem);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
raw->transfermem_size = transfermem_size;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nvSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
static Result _nvCmdInitialize(Handle proc, Handle sharedmem, u32 transfermem_size)
|
||||
{
|
||||
return serviceDispatchIn(&g_nvSrv, 3, transfermem_size,
|
||||
.in_num_handles = 2,
|
||||
.in_handles = { proc, sharedmem },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _nvSetClientPID(u64 AppletResourceUserId) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 AppletResourceUserId;
|
||||
} *raw;
|
||||
|
||||
ipcSendPid(&c);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 8;
|
||||
raw->AppletResourceUserId = AppletResourceUserId;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nvSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
static Result _nvSetClientPID(u64 AppletResourceUserId)
|
||||
{
|
||||
return serviceDispatchIn(&g_nvSrv, 8, AppletResourceUserId, .in_send_pid = true);
|
||||
}
|
||||
|
||||
Result nvOpen(u32 *fd, const char *devicepath) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
Result nvOpen(u32 *fd, const char *devicepath)
|
||||
{
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
u32 fd;
|
||||
u32 error;
|
||||
} out;
|
||||
|
||||
ipcAddSendBuffer(&c, devicepath, strlen(devicepath), 0);
|
||||
Result rc = serviceDispatchOut(&g_nvSrv, 0, out,
|
||||
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
|
||||
.buffers = { { devicepath, strlen(devicepath) } },
|
||||
);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(out.error);
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nvSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 fd;
|
||||
u32 error;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(resp->error);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
*fd = resp->fd;
|
||||
}
|
||||
if (R_SUCCEEDED(rc) && fd)
|
||||
*fd = out.fd;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -215,194 +126,120 @@ static inline Service* _nvGetSessionForRequest(u32 request)
|
||||
return &g_nvSrv;
|
||||
}
|
||||
|
||||
Result nvIoctl(u32 fd, u32 request, void* argp) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 fd;
|
||||
u32 request;
|
||||
} *raw;
|
||||
|
||||
Result nvIoctl(u32 fd, u32 request, void* argp)
|
||||
{
|
||||
size_t bufsize = _NV_IOC_SIZE(request);
|
||||
u32 dir = _NV_IOC_DIR(request);
|
||||
|
||||
void* buf_send = NULL, *buf_recv = NULL;
|
||||
void *buf_send = NULL, *buf_recv = NULL;
|
||||
size_t buf_send_size = 0, buf_recv_size = 0;
|
||||
|
||||
if(dir & _NV_IOC_WRITE) {
|
||||
if (dir & _NV_IOC_WRITE) {
|
||||
buf_send = argp;
|
||||
buf_send_size = bufsize;
|
||||
}
|
||||
|
||||
if(dir & _NV_IOC_READ) {
|
||||
if (dir & _NV_IOC_READ) {
|
||||
buf_recv = argp;
|
||||
buf_recv_size = bufsize;
|
||||
}
|
||||
|
||||
ipcAddSendSmart(&c, g_nvIpcBufferSize, buf_send, buf_send_size, 0);
|
||||
ipcAddRecvSmart(&c, g_nvIpcBufferSize, buf_recv, buf_recv_size, 0);
|
||||
const struct {
|
||||
u32 fd;
|
||||
u32 request;
|
||||
} in = { fd, request };
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->fd = fd;
|
||||
raw->request = request;
|
||||
u32 error = 0;
|
||||
Result rc = serviceDispatchInOut(_nvGetSessionForRequest(request), 1, in, error,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ buf_send, buf_send_size },
|
||||
{ buf_recv, buf_recv_size },
|
||||
},
|
||||
);
|
||||
|
||||
Result rc = serviceIpcDispatch(_nvGetSessionForRequest(request));
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 error;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(resp->error);
|
||||
}
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(error);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nvIoctl2(u32 fd, u32 request, void* argp, const void* inbuf, size_t inbuf_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 fd;
|
||||
u32 request;
|
||||
} *raw;
|
||||
|
||||
Result nvIoctl2(u32 fd, u32 request, void* argp, const void* inbuf, size_t inbuf_size)
|
||||
{
|
||||
size_t bufsize = _NV_IOC_SIZE(request);
|
||||
u32 dir = _NV_IOC_DIR(request);
|
||||
|
||||
void* buf_send = NULL, *buf_recv = NULL;
|
||||
void *buf_send = NULL, *buf_recv = NULL;
|
||||
size_t buf_send_size = 0, buf_recv_size = 0;
|
||||
|
||||
if(dir & _NV_IOC_WRITE) {
|
||||
if (dir & _NV_IOC_WRITE) {
|
||||
buf_send = argp;
|
||||
buf_send_size = bufsize;
|
||||
}
|
||||
|
||||
if(dir & _NV_IOC_READ) {
|
||||
if (dir & _NV_IOC_READ) {
|
||||
buf_recv = argp;
|
||||
buf_recv_size = bufsize;
|
||||
}
|
||||
|
||||
ipcAddSendSmart(&c, g_nvIpcBufferSize, buf_send, buf_send_size, 0);
|
||||
ipcAddSendSmart(&c, g_nvIpcBufferSize, inbuf, inbuf_size, 1);
|
||||
ipcAddRecvSmart(&c, g_nvIpcBufferSize, buf_recv, buf_recv_size, 0);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 11;
|
||||
raw->fd = fd;
|
||||
raw->request = request;
|
||||
|
||||
Result rc = serviceIpcDispatch(_nvGetSessionForRequest(request));
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 error;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(resp->error);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nvClose(u32 fd) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
const struct {
|
||||
u32 fd;
|
||||
} *raw;
|
||||
u32 request;
|
||||
} in = { fd, request };
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->fd = fd;
|
||||
u32 error = 0;
|
||||
Result rc = serviceDispatchInOut(_nvGetSessionForRequest(request), 11, in, error,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ buf_send, buf_send_size },
|
||||
{ inbuf, inbuf_size },
|
||||
{ buf_recv, buf_recv_size },
|
||||
},
|
||||
);
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nvSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 error;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(resp->error);
|
||||
}
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(error);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nvQueryEvent(u32 fd, u32 event_id, Event *event_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Result nvClose(u32 fd)
|
||||
{
|
||||
u32 error = 0;
|
||||
Result rc = serviceDispatchInOut(&g_nvSrv, 2, fd, error);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(error);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result nvQueryEvent(u32 fd, u32 event_id, Event *event_out)
|
||||
{
|
||||
const struct {
|
||||
u32 fd;
|
||||
u32 event_id;
|
||||
} *raw;
|
||||
} in = { fd, event_id };
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
raw->fd = fd;
|
||||
raw->event_id = event_id;
|
||||
u32 error = 0;
|
||||
Handle event;
|
||||
Result rc = serviceDispatchInOut(&g_nvSrv, 4, in, error,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &event,
|
||||
);
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_nvSrv);
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(error);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 error;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = nvConvertError(resp->error);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(event_out, r.Handles[0], true);
|
||||
}
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(event_out, event, true);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1,837 +1,160 @@
|
||||
// Copyright 2017 plutoo
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/pm.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_pmdmntSrv, g_pmshellSrv, g_pminfoSrv, g_pmbmSrv;
|
||||
static u64 g_pmdmntRefCnt, g_pmshellRefCnt, g_pminfoRefCnt, g_pmbmRefCnt;
|
||||
|
||||
Result pmdmntInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_pmdmntRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_pmdmntSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_pmdmntSrv, "pm:dmnt");
|
||||
#define PM_GENERATE_SERVICE_INIT(name) \
|
||||
static Service g_pm##name##Srv; \
|
||||
\
|
||||
NX_GENERATE_SERVICE_GUARD(pm##name); \
|
||||
\
|
||||
Result _pm##name##Initialize(void) { \
|
||||
return smGetService(&g_pm##name##Srv, "pm:"#name); \
|
||||
} \
|
||||
\
|
||||
void _pm##name##Cleanup(void) { \
|
||||
serviceClose(&g_pm##name##Srv); \
|
||||
} \
|
||||
\
|
||||
Service* pm##name##GetServiceSession(void) { \
|
||||
return &g_pm##name##Srv; \
|
||||
}
|
||||
|
||||
void pmdmntExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_pmdmntRefCnt) == 0) {
|
||||
serviceClose(&g_pmdmntSrv);
|
||||
}
|
||||
}
|
||||
|
||||
Service* pmdmntGetServiceSession(void) {
|
||||
return &g_pmdmntSrv;
|
||||
}
|
||||
|
||||
Result pminfoInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_pminfoRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_pminfoSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_pminfoSrv, "pm:info");
|
||||
}
|
||||
|
||||
void pminfoExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_pminfoRefCnt) == 0) {
|
||||
serviceClose(&g_pminfoSrv);
|
||||
}
|
||||
}
|
||||
|
||||
Service* pminfoGetServiceSession(void)
|
||||
{
|
||||
return &g_pminfoSrv;
|
||||
}
|
||||
|
||||
Result pmshellInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_pmshellRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_pmshellSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_pmshellSrv, "pm:shell");
|
||||
}
|
||||
|
||||
void pmshellExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_pmshellRefCnt) == 0) {
|
||||
serviceClose(&g_pmshellSrv);
|
||||
}
|
||||
}
|
||||
|
||||
Service* pmshellGetServiceSession(void)
|
||||
{
|
||||
return &g_pmshellSrv;
|
||||
}
|
||||
|
||||
Result pmbmInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_pmbmRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_pmbmSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_pmbmSrv, "pm:bm");
|
||||
}
|
||||
|
||||
void pmbmExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_pmbmRefCnt) == 0) {
|
||||
serviceClose(&g_pmbmSrv);
|
||||
}
|
||||
}
|
||||
|
||||
Service* pmbmGetServiceSession(void)
|
||||
{
|
||||
return &g_pmbmSrv;
|
||||
}
|
||||
PM_GENERATE_SERVICE_INIT(dmnt);
|
||||
PM_GENERATE_SERVICE_INIT(shell);
|
||||
PM_GENERATE_SERVICE_INIT(info);
|
||||
PM_GENERATE_SERVICE_INIT(bm);
|
||||
|
||||
Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, out_pids, sizeof(*out_pids) * max_pids, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 0 : 1;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_count) *out_count = resp->out_count;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 0 : 1;
|
||||
return serviceDispatchOut(&g_pmdmntSrv, cmd_id, *out_count,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ out_pids, max_pids * sizeof(*out_pids) },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Result pmdmntStartProcess(u64 pid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 1 : 2;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 1 : 2;
|
||||
return serviceDispatchIn(&g_pmdmntSrv, cmd_id, pid);
|
||||
}
|
||||
|
||||
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 title_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 2 : 3;
|
||||
raw->title_id = title_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*pid_out = resp->pid;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 2 : 3;
|
||||
return serviceDispatchInOut(&g_pmdmntSrv, cmd_id, title_id, *pid_out);
|
||||
}
|
||||
|
||||
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 title_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 3 : 4;
|
||||
raw->title_id = title_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pminfoGetTitleId(u64* title_id_out, u64 pid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pminfoSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 title_id;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*title_id_out = resp->title_id;
|
||||
}
|
||||
}
|
||||
Result pmdmntEnableDebugForTitleId(Event* out_event, u64 title_id) {
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 3 : 4;
|
||||
Handle event = INVALID_HANDLE;
|
||||
Result rc = serviceDispatchIn(&g_pmdmntSrv, cmd_id, title_id,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &event,
|
||||
);
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(out_event, event, true);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pmdmntGetApplicationPid(u64* pid_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 4 : 5;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*pid_out = resp->pid;
|
||||
}
|
||||
}
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 4 : 5;
|
||||
return serviceDispatchOut(&g_pmdmntSrv, cmd_id, *pid_out);
|
||||
}
|
||||
|
||||
Result pmdmntEnableDebugForApplication(Event* out_event) {
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 5 : 6;
|
||||
Handle event = INVALID_HANDLE;
|
||||
Result rc = serviceDispatch(&g_pmdmntSrv, cmd_id,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &event,
|
||||
);
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(out_event, event, true);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pmdmntEnableDebugForApplication(Handle* handle_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 5 : 6;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pmdmntDisableDebug(void) {
|
||||
Result pmdmntDisableDebug(u32 which) {
|
||||
if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_pmdmntSrv, 6, which);
|
||||
}
|
||||
|
||||
Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
const struct {
|
||||
u32 launch_flags;
|
||||
u64 titleID;
|
||||
u64 storageID;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->launch_flags = launch_flags;
|
||||
raw->titleID = titleID;
|
||||
raw->storageID = storageID;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && pid) *pid = resp->pid;
|
||||
}
|
||||
|
||||
return rc;
|
||||
} in = { launch_flags, titleID, storageID };
|
||||
return serviceDispatchInOut(&g_pmshellSrv, 0, in, *pid);
|
||||
}
|
||||
|
||||
Result pmshellTerminateProcessByProcessId(u64 processID) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 processID;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->processID = processID;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_pmshellSrv, 1, processID);
|
||||
}
|
||||
|
||||
Result pmshellTerminateProcessByTitleId(u64 titleID) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 titleID;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->titleID = titleID;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_pmshellSrv, 2, titleID);
|
||||
}
|
||||
|
||||
Result pmshellGetProcessEvent(Event* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(out, r.Handles[0], true);
|
||||
}
|
||||
}
|
||||
|
||||
Result pmshellGetProcessEvent(Event* out_event) {
|
||||
Handle event = INVALID_HANDLE;
|
||||
Result rc = serviceDispatch(&g_pmshellSrv, 3,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &event,
|
||||
);
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(out_event, event, true);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result pmshellGetProcessEventInfo(PmProcessEventInfo* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 event;
|
||||
u32 pad;
|
||||
u64 process_id;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out) {
|
||||
out->event = (PmProcessEvent)resp->event;
|
||||
out->process_id = resp->process_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
_Static_assert(sizeof(out->event) == sizeof(u32), "PmProcessEvent");
|
||||
return serviceDispatchOut(&g_pmshellSrv, 4, *out);
|
||||
}
|
||||
|
||||
Result pmshellFinalizeDeadProcess(u64 pid) {
|
||||
if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_pmshellSrv, 5, pid);
|
||||
}
|
||||
|
||||
Result pmshellClearProcessExceptionOccurred(u64 pid) {
|
||||
if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_pmshellSrv, 6, pid);
|
||||
}
|
||||
|
||||
Result pmshellNotifyBootFinished(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 5 : 7;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 5 : 7;
|
||||
return serviceDispatch(&g_pmshellSrv, cmd_id);
|
||||
}
|
||||
|
||||
Result pmshellGetApplicationPid(u64* pid_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 6 : 8;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 pid;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*pid_out = resp->pid;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 6 : 8;
|
||||
return serviceDispatchOut(&g_pmshellSrv, cmd_id, *pid_out);
|
||||
}
|
||||
|
||||
Result pmshellBoostSystemMemoryResourceLimit(u64 boost_size) {
|
||||
if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 boost_size;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(5,0,0) ? 7 : 9;
|
||||
raw->boost_size = boost_size;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 7 : 9;
|
||||
return serviceDispatchIn(&g_pmshellSrv, cmd_id, boost_size);
|
||||
}
|
||||
|
||||
Result pmshellBoostSystemThreadResourceLimit(void) {
|
||||
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
return serviceDispatch(&g_pmshellSrv, 8);
|
||||
}
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 8;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmshellSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result pminfoGetTitleId(u64* title_id_out, u64 pid) {
|
||||
return serviceDispatchInOut(&g_pminfoSrv, 0, pid, *title_id_out);
|
||||
}
|
||||
|
||||
Result pmbmGetBootMode(PmBootMode *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmbmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 boot_mode;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) {
|
||||
*out = (PmBootMode)resp->boot_mode;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
_Static_assert(sizeof(*out) == sizeof(u32), "PmBootMode");
|
||||
return serviceDispatchOut(&g_pmbmSrv, 0, *out);
|
||||
}
|
||||
|
||||
Result pmbmSetMaintenanceBoot(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_pmbmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatch(&g_pmbmSrv, 1);
|
||||
}
|
||||
|
||||
@ -1,135 +1,80 @@
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "kernel/event.h"
|
||||
#include "services/psm.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_psmSrv;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static Result _psmOpenSession(Service* out);
|
||||
static Result _psmOpenSession(Service* srv_out);
|
||||
static Result _psmBindStateChangeEvent(PsmSession* s, Event* event_out);
|
||||
|
||||
static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag);
|
||||
static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag);
|
||||
static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag);
|
||||
|
||||
Result psmInitialize(void) {
|
||||
Result rc = 0;
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
NX_GENERATE_SERVICE_GUARD(psm);
|
||||
|
||||
if (serviceIsActive(&g_psmSrv))
|
||||
return 0;
|
||||
|
||||
rc = smGetService(&g_psmSrv, "psm");
|
||||
|
||||
if (R_FAILED(rc)) psmExit();
|
||||
|
||||
return rc;
|
||||
Result _psmInitialize(void) {
|
||||
return smGetService(&g_psmSrv, "psm");
|
||||
}
|
||||
|
||||
void psmExit(void) {
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_psmSrv);
|
||||
}
|
||||
void _psmCleanup(void) {
|
||||
serviceClose(&g_psmSrv);
|
||||
}
|
||||
|
||||
Service* psmGetServiceSession(void) {
|
||||
return &g_psmSrv;
|
||||
}
|
||||
|
||||
static Result _psmGetOutU32(u64 cmd_id, u32 *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_psmSrv);
|
||||
|
||||
if(R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
static Result _psmCmdNoIO(Service* srv, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id);
|
||||
}
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp;
|
||||
static Result _psmCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) {
|
||||
Handle event = INVALID_HANDLE;
|
||||
Result rc = serviceDispatch(srv, cmd_id,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = &event,
|
||||
);
|
||||
|
||||
serviceIpcParse(&g_psmSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(out_event, event, autoclear);
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = resp->out;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _psmCmdInU8NoOut(Service* srv, u8 inval, u32 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result _psmCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
|
||||
return _psmCmdInU8NoOut(srv, inval!=0, cmd_id);
|
||||
}
|
||||
|
||||
static Result _psmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
Result psmGetBatteryChargePercentage(u32 *out) {
|
||||
return _psmGetOutU32(0, out);
|
||||
return _psmCmdNoInOutU32(&g_psmSrv, out, 0);
|
||||
}
|
||||
|
||||
Result psmGetChargerType(ChargerType *out) {
|
||||
return _psmGetOutU32(1, out);
|
||||
return _psmCmdNoInOutU32(&g_psmSrv, out, 1);
|
||||
}
|
||||
|
||||
Result psmGetBatteryVoltageState(PsmBatteryVoltageState *out) {
|
||||
u32 state;
|
||||
Result rc = _psmGetOutU32(12, &state);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out = (PsmBatteryVoltageState)state;
|
||||
}
|
||||
Result rc = _psmCmdNoInOutU32(&g_psmSrv, &state, 12);
|
||||
if (R_SUCCEEDED(rc) && out) *out = state;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _psmOpenSession(Service* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 7;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_psmSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_psmSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
serviceCreateSubservice(out, &g_psmSrv, &r, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
static Result _psmOpenSession(Service* srv_out) {
|
||||
return serviceDispatch(&g_psmSrv, 7,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
Result psmBindStateChangeEvent(PsmSession* s, bool ChargerType, bool PowerSupply, bool BatteryVoltage) {
|
||||
@ -162,71 +107,12 @@ Result psmWaitStateChangeEvent(PsmSession* s, u64 timeout) {
|
||||
}
|
||||
|
||||
static Result _psmBindStateChangeEvent(PsmSession* s, Event *event_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&s->s);
|
||||
|
||||
if(R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&s->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(event_out, r.Handles[0], false);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _psmCmdGetEvent(&s->s, event_out, false, 0);
|
||||
}
|
||||
|
||||
Result psmUnbindStateChangeEvent(PsmSession* s) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
Result rc = serviceIpcDispatch(&s->s);
|
||||
|
||||
if(R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&s->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
Result rc=0;
|
||||
if (serviceIsActive(&s->s)) rc = _psmCmdNoIO(&s->s, 1);
|
||||
|
||||
eventClose(&s->StateChangeEvent);
|
||||
serviceClose(&s->s);
|
||||
@ -234,49 +120,18 @@ Result psmUnbindStateChangeEvent(PsmSession* s) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _psmSetEventEnabled(PsmSession* s, u64 cmd_id, bool flag) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u8 flag;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->flag = (flag != 0);
|
||||
|
||||
Result rc = serviceIpcDispatch(&s->s);
|
||||
|
||||
if(R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&s->s, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
static Result _psmSetEventEnabled(PsmSession* s, bool flag, u32 cmd_id) {
|
||||
return _psmCmdInBoolNoOut(&s->s, flag, cmd_id);
|
||||
}
|
||||
|
||||
static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag) {
|
||||
return _psmSetEventEnabled(s, 2, flag);
|
||||
return _psmSetEventEnabled(s, flag, 2);
|
||||
}
|
||||
|
||||
static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag) {
|
||||
return _psmSetEventEnabled(s, 3, flag);
|
||||
return _psmSetEventEnabled(s, flag, 3);
|
||||
}
|
||||
|
||||
static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag) {
|
||||
return _psmSetEventEnabled(s, 4, flag);
|
||||
return _psmSetEventEnabled(s, flag, 4);
|
||||
}
|
||||
|
||||
@ -1,86 +1,60 @@
|
||||
// Copyright 2018 SciresM
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/ro.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_roSrv, g_ro1Srv, g_dmntSrv;
|
||||
static u64 g_roRefCnt, g_ro1RefCnt, g_dmntRefCnt;
|
||||
|
||||
static Result _rosrvInitialize(Service* srv);
|
||||
static Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
|
||||
static Result _rosrvUnloadNro(Service* srv, u64 nro_address);
|
||||
static Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size);
|
||||
static Result _rosrvUnloadNrr(Service* srv, u64 nrr_address);
|
||||
NX_GENERATE_SERVICE_GUARD(ldrRo);
|
||||
NX_GENERATE_SERVICE_GUARD(ro1);
|
||||
NX_GENERATE_SERVICE_GUARD(roDmnt);
|
||||
|
||||
Result ldrRoInitialize(void) {
|
||||
atomicIncrement64(&g_roRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_roSrv))
|
||||
return 0;
|
||||
NX_INLINE Result _rosrvInitialize(Service* srv);
|
||||
NX_INLINE Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
|
||||
NX_INLINE Result _rosrvUnloadNro(Service* srv, u64 nro_address);
|
||||
NX_INLINE Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size);
|
||||
NX_INLINE Result _rosrvUnloadNrr(Service* srv, u64 nrr_address);
|
||||
|
||||
Result _ldrRoInitialize(void) {
|
||||
Result rc = smGetService(&g_roSrv, "ldr:ro");
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _rosrvInitialize(&g_roSrv);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ldrRoExit(void) {
|
||||
if (atomicDecrement64(&g_roRefCnt) == 0)
|
||||
serviceClose(&g_roSrv);
|
||||
void _ldrRoCleanup(void) {
|
||||
serviceClose(&g_roSrv);
|
||||
}
|
||||
|
||||
Service* ldrRoGetServiceSession(void) {
|
||||
return &g_roSrv;
|
||||
}
|
||||
|
||||
Result ro1Initialize(void) {
|
||||
Result _ro1Initialize(void) {
|
||||
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
atomicIncrement64(&g_ro1RefCnt);
|
||||
|
||||
if (serviceIsActive(&g_ro1Srv))
|
||||
return 0;
|
||||
|
||||
Result rc = smGetService(&g_ro1Srv, "ro:1");
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _rosrvInitialize(&g_ro1Srv);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ro1Exit(void) {
|
||||
if (atomicDecrement64(&g_ro1RefCnt) == 0)
|
||||
serviceClose(&g_ro1Srv);
|
||||
void _ro1Cleanup(void) {
|
||||
serviceClose(&g_ro1Srv);
|
||||
}
|
||||
|
||||
Service* ro1GetServiceSession(void) {
|
||||
return &g_ro1Srv;
|
||||
}
|
||||
|
||||
Result roDmntInitialize(void) {
|
||||
Result _roDmntInitialize(void) {
|
||||
if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
atomicIncrement64(&g_dmntRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_dmntSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_dmntSrv, "ro:dmnt");
|
||||
}
|
||||
|
||||
void roDmntExit(void) {
|
||||
if (atomicDecrement64(&g_dmntRefCnt) == 0)
|
||||
serviceClose(&g_dmntSrv);
|
||||
void _roDmntCleanup(void) {
|
||||
serviceClose(&g_dmntSrv);
|
||||
}
|
||||
|
||||
Service* roDmntGetServiceSession(void) {
|
||||
@ -88,198 +62,46 @@ Service* roDmntGetServiceSession(void) {
|
||||
}
|
||||
|
||||
Result _rosrvInitialize(Service* srv) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendHandleCopy(&c, CUR_PROCESS_HANDLE);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatch(srv, 4,
|
||||
.in_num_handles = 1,
|
||||
.in_handles = { CUR_PROCESS_HANDLE },
|
||||
);
|
||||
}
|
||||
|
||||
Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
const struct {
|
||||
u64 pid_placeholder;
|
||||
u64 nro_address;
|
||||
u64 nro_size;
|
||||
u64 bss_address;
|
||||
u64 bss_size;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->pid = 0;
|
||||
raw->nro_address = nro_address;
|
||||
raw->nro_size = nro_size;
|
||||
raw->bss_address = bss_address;
|
||||
raw->bss_size = bss_size;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 out_address;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_address) *out_address = resp->out_address;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
} in = { 0, nro_address, nro_size, bss_address, bss_size };
|
||||
return serviceDispatchInOut(srv, 0, in, *out_address, .in_send_pid = true);
|
||||
}
|
||||
|
||||
Result _rosrvUnloadNro(Service* srv, u64 nro_address) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
const struct {
|
||||
u64 pid_placeholder;
|
||||
u64 nro_address;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->pid = 0;
|
||||
raw->nro_address = nro_address;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
} in = { 0, nro_address };
|
||||
return serviceDispatchIn(srv, 1, in, .in_send_pid = true);
|
||||
}
|
||||
|
||||
Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
const struct {
|
||||
u64 pid_placeholder;
|
||||
u64 nrr_address;
|
||||
u64 nrr_size;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->pid = 0;
|
||||
raw->nrr_address = nrr_address;
|
||||
raw->nrr_size = nrr_size;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
} in = { 0, nrr_address, nrr_size };
|
||||
return serviceDispatchIn(srv, cmd_id, in, .in_send_pid = true);
|
||||
}
|
||||
|
||||
Result _rosrvUnloadNrr(Service* srv, u64 nrr_address) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
const struct {
|
||||
u64 pid_placeholder;
|
||||
u64 nrr_address;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
raw->pid = 0;
|
||||
raw->nrr_address = nrr_address;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(srv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
} in = { 0, nrr_address };
|
||||
return serviceDispatchIn(srv, 3, in, .in_send_pid = true);
|
||||
}
|
||||
|
||||
Result ldrRoLoadNro(u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
@ -326,41 +148,12 @@ Result ro1LoadNrrEx(u64 nrr_address, u64 nrr_size) {
|
||||
}
|
||||
|
||||
Result roDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t max_out_modules, u32 *num_out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddRecvBuffer(&c, out_module_infos, max_out_modules * sizeof(*out_module_infos), BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->pid = pid;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 num_out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc) && num_out != NULL) {
|
||||
*num_out = resp->num_out;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(&g_dmntSrv, 0, pid, *num_out,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ out_module_infos, max_out_modules * sizeof(*out_module_infos) },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
56
nx/source/services/service_guard.h
Normal file
56
nx/source/services/service_guard.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "kernel/mutex.h"
|
||||
#include "sf/service.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
typedef struct ServiceGuard {
|
||||
Mutex mutex;
|
||||
u32 refCount;
|
||||
} ServiceGuard;
|
||||
|
||||
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
|
||||
{
|
||||
mutexLock(&g->mutex);
|
||||
return (g->refCount++) == 0;
|
||||
}
|
||||
|
||||
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
|
||||
{
|
||||
if (R_FAILED(rc)) {
|
||||
cleanupFunc();
|
||||
--g->refCount;
|
||||
}
|
||||
mutexUnlock(&g->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
|
||||
{
|
||||
mutexLock(&g->mutex);
|
||||
if (g->refCount && (--g->refCount) == 0)
|
||||
cleanupFunc();
|
||||
mutexUnlock(&g->mutex);
|
||||
}
|
||||
|
||||
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
|
||||
\
|
||||
static ServiceGuard g_##name##Guard; \
|
||||
NX_INLINE Result _##name##Initialize _paramdecl; \
|
||||
static void _##name##Cleanup(void); \
|
||||
\
|
||||
Result name##Initialize _paramdecl \
|
||||
{ \
|
||||
Result rc = 0; \
|
||||
if (serviceGuardBeginInit(&g_##name##Guard)) \
|
||||
rc = _##name##Initialize _parampass; \
|
||||
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
|
||||
} \
|
||||
\
|
||||
void name##Exit(void) \
|
||||
{ \
|
||||
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
|
||||
}
|
||||
|
||||
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
|
||||
@ -1,24 +1,12 @@
|
||||
/**
|
||||
* @file set.h
|
||||
* @brief Settings services IPC wrapper.
|
||||
* @author plutoo
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/set.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/applet.h"
|
||||
|
||||
static Service g_setSrv;
|
||||
static Service g_setsysSrv;
|
||||
static u64 g_refCnt;
|
||||
static u64 g_refCntSys;
|
||||
|
||||
static bool g_setLanguageCodesInitialized;
|
||||
static u64 g_setLanguageCodes[0x40];
|
||||
@ -26,50 +14,83 @@ static s32 g_setLanguageCodesTotal;
|
||||
|
||||
static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode);
|
||||
|
||||
Result setInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_setSrv))
|
||||
return 0;
|
||||
NX_GENERATE_SERVICE_GUARD(set);
|
||||
|
||||
Result _setInitialize(void) {
|
||||
g_setLanguageCodesInitialized = 0;
|
||||
|
||||
return smGetService(&g_setSrv, "set");
|
||||
}
|
||||
|
||||
void setExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_setSrv);
|
||||
}
|
||||
void _setCleanup(void) {
|
||||
serviceClose(&g_setSrv);
|
||||
}
|
||||
|
||||
Service* setGetServiceSession(void) {
|
||||
return &g_setSrv;
|
||||
}
|
||||
|
||||
Result setsysInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCntSys);
|
||||
|
||||
if (serviceIsActive(&g_setsysSrv))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
NX_GENERATE_SERVICE_GUARD(setsys);
|
||||
|
||||
Result _setsysInitialize(void) {
|
||||
return smGetService(&g_setsysSrv, "set:sys");
|
||||
}
|
||||
|
||||
void setsysExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCntSys) == 0) {
|
||||
serviceClose(&g_setsysSrv);
|
||||
}
|
||||
void _setsysCleanup(void) {
|
||||
serviceClose(&g_setsysSrv);
|
||||
}
|
||||
|
||||
Service* setsysGetSessionService(void) {
|
||||
Service* setsysGetServiceSession(void) {
|
||||
return &g_setsysSrv;
|
||||
}
|
||||
|
||||
static Result _setCmdGetHandle(Service* srv, Handle* handle_out, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
|
||||
.out_handles = handle_out,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _setCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) {
|
||||
Handle tmp_handle = INVALID_HANDLE;
|
||||
Result rc = 0;
|
||||
|
||||
rc = _setCmdGetHandle(srv, &tmp_handle, cmd_id);
|
||||
if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, autoclear);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _setCmdNoInOut64(Service* srv, u64 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _setCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _setCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _setCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
|
||||
u8 tmp=0;
|
||||
Result rc = _setCmdNoInOutU8(srv, &tmp, cmd_id);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp!=0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _setCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result _setCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
|
||||
return _setCmdInU8NoOut(srv, inval!=0, cmd_id);
|
||||
}
|
||||
|
||||
static Result _setCmdInU32NoOut(Service* srv, u32 inval, u32 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result setInitializeLanguageCodesCache(void) {
|
||||
if (g_setLanguageCodesInitialized) return 0;
|
||||
Result rc = 0;
|
||||
@ -84,7 +105,7 @@ static Result setInitializeLanguageCodesCache(void) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setMakeLanguage(u64 LanguageCode, s32 *Language) {
|
||||
Result setMakeLanguage(u64 LanguageCode, SetLanguage *Language) {
|
||||
Result rc = setInitializeLanguageCodesCache();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
@ -100,7 +121,7 @@ Result setMakeLanguage(u64 LanguageCode, s32 *Language) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode) {
|
||||
Result setMakeLanguageCode(SetLanguage Language, u64 *LanguageCode) {
|
||||
Result rc = setInitializeLanguageCodesCache();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
@ -126,43 +147,10 @@ Result setGetSystemLanguage(u64 *LanguageCode) {
|
||||
}
|
||||
|
||||
Result setGetLanguageCode(u64 *LanguageCode) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 LanguageCode;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _setCmdNoInOut64(&g_setSrv, LanguageCode, 0);
|
||||
}
|
||||
|
||||
Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
Result rc=0;
|
||||
bool new_cmd = hosversionAtLeast(4,0,0);
|
||||
|
||||
@ -175,260 +163,38 @@ Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size
|
||||
if (max_entries > (size_t)tmptotal) max_entries = (size_t)tmptotal;
|
||||
}
|
||||
|
||||
size_t bufsize = max_entries*sizeof(u64);
|
||||
|
||||
if (!new_cmd) {
|
||||
ipcAddRecvStatic(&c, LanguageCodes, bufsize, 0);
|
||||
}
|
||||
else {
|
||||
ipcAddRecvBuffer(&c, LanguageCodes, bufsize, 0);
|
||||
}
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = new_cmd ? 5 : 1;
|
||||
|
||||
rc = serviceIpcDispatch(&g_setSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
s32 total_entries;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchOut(&g_setSrv, new_cmd ? 5 : 1, *total_entries,
|
||||
.buffer_attrs = { (new_cmd ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcPointer) | SfBufferAttr_Out },
|
||||
.buffers = { { LanguageCodes, max_entries*sizeof(u64) } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
s32 Language;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->Language = Language;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 LanguageCode;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(&g_setSrv, 2, Language, *LanguageCode);
|
||||
}
|
||||
|
||||
Result setGetAvailableLanguageCodeCount(s32 *total) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionAtLeast(4,0,0) ? 6 : 3;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
s32 total;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && total) {
|
||||
*total = resp->total;
|
||||
if (*total < 0) *total = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Result rc = _setCmdNoInOutU32(&g_setSrv, (u32*)total, hosversionAtLeast(4,0,0) ? 6 : 3);
|
||||
if (R_SUCCEEDED(rc) && total && *total < 0) *total = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setGetRegionCode(SetRegion *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
s32 RegionCode;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out) *out = resp->RegionCode;
|
||||
}
|
||||
|
||||
s32 code=0;
|
||||
Result rc = _setCmdNoInOutU32(&g_setSrv, (u32*)&code, 4);
|
||||
if (R_SUCCEEDED(rc) && out) *out = code;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setsysGetColorSetId(ColorSetId *out)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 23;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 color_set;
|
||||
} *resp = r.Raw;
|
||||
|
||||
*out = resp->color_set;
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
Result setsysGetColorSetId(ColorSetId *out) {
|
||||
u32 color_set=0;
|
||||
Result rc = _setCmdNoInOutU32(&g_setsysSrv, &color_set, 23);
|
||||
if (R_SUCCEEDED(rc) && out) *out = color_set;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setsysSetColorSetId(ColorSetId id)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
s32 id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 24;
|
||||
raw->id = id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size) {
|
||||
char send_name[SET_MAX_NAME_SIZE];
|
||||
char send_item_key[SET_MAX_NAME_SIZE];
|
||||
|
||||
memset(send_name, 0, SET_MAX_NAME_SIZE);
|
||||
memset(send_item_key, 0, SET_MAX_NAME_SIZE);
|
||||
strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
|
||||
strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0);
|
||||
ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0);
|
||||
ipcAddRecvBuffer(&c, value_out, value_out_size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 38;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result setsysSetColorSetId(ColorSetId id) {
|
||||
return _setCmdInU32NoOut(&g_setsysSrv, id, 24);
|
||||
}
|
||||
|
||||
Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u64 *size_out) {
|
||||
@ -439,178 +205,66 @@ Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u6
|
||||
memset(send_item_key, 0, SET_MAX_NAME_SIZE);
|
||||
strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
|
||||
strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
|
||||
|
||||
return serviceDispatchOut(&g_setsysSrv, 37, *size_out,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_In,
|
||||
},
|
||||
.buffers = {
|
||||
{ send_name, SET_MAX_NAME_SIZE },
|
||||
{ send_item_key, SET_MAX_NAME_SIZE },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size, u64 *size_out) {
|
||||
char send_name[SET_MAX_NAME_SIZE];
|
||||
char send_item_key[SET_MAX_NAME_SIZE];
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0);
|
||||
ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0);
|
||||
memset(send_name, 0, SET_MAX_NAME_SIZE);
|
||||
memset(send_item_key, 0, SET_MAX_NAME_SIZE);
|
||||
strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
|
||||
strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 37;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && size_out) *size_out = resp->size;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchOut(&g_setsysSrv, 38, *size_out,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ send_name, SET_MAX_NAME_SIZE },
|
||||
{ send_item_key, SET_MAX_NAME_SIZE },
|
||||
{ value_out, value_out_size },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Result setsysGetSerialNumber(char *serial) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
char out[0x18]={0};
|
||||
|
||||
if (serial) memset(serial, 0, 0x19);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 68;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
char serial[0x18];
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && serial)
|
||||
memcpy(serial, resp->serial, 0x18);
|
||||
Result rc = serviceDispatchOut(&g_setsysSrv, 68, out);
|
||||
if (R_SUCCEEDED(rc) && serial) {
|
||||
memcpy(serial, out, 0x18);
|
||||
serial[0x18]=0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setsysGetFlag(SetSysFlag flag, bool *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = flag;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 flag;
|
||||
} *resp = r.Raw;
|
||||
|
||||
*out = resp->flag;
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _setCmdNoInOutBool(&g_setsysSrv, out, flag);
|
||||
}
|
||||
|
||||
Result setsysSetFlag(SetSysFlag flag, bool enable) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u8 flag;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = flag + 1;
|
||||
raw->flag = enable;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 flag;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _setCmdInBoolNoOut(&g_setsysSrv, enable, flag + 1);
|
||||
}
|
||||
|
||||
static Result _setsysGetFirmwareVersionImpl(SetSysFirmwareVersion *out, u32 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvStatic(&c, out, sizeof(*out), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_setsysSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_setsysSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
return serviceDispatch(&g_setsysSrv, cmd_id,
|
||||
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { out, sizeof(*out) } },
|
||||
);
|
||||
}
|
||||
|
||||
Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) {
|
||||
@ -622,143 +276,35 @@ Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) {
|
||||
}
|
||||
}
|
||||
|
||||
Result setsysBindFatalDirtyFlagEvent(Event *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 93;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
eventLoadRemote(out, r.Handles[0], false);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result setsysBindFatalDirtyFlagEvent(Event *out_event) {
|
||||
return _setCmdGetEvent(&g_setsysSrv, out_event, false, 93);
|
||||
}
|
||||
|
||||
Result setsysGetFatalDirtyFlags(u64 *flags_0, u64 *flags_1) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 94;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 flags_0;
|
||||
u64 flags_1;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*flags_0 = resp->flags_0;
|
||||
*flags_1 = resp->flags_1;
|
||||
}
|
||||
}
|
||||
u64 flags_0;
|
||||
u64 flags_1;
|
||||
} out;
|
||||
|
||||
Result rc = serviceDispatchOut(&g_setsysSrv, 94, out);
|
||||
if (R_SUCCEEDED(rc) && flags_0) *flags_0 = out.flags_0;
|
||||
if (R_SUCCEEDED(rc) && flags_1) *flags_1 = out.flags_1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setsysGetDeviceNickname(char* nickname) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddRecvBuffer(&c, nickname, SET_MAX_NICKNAME_SIZE, BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 77;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatch(&g_setsysSrv, 77,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { nickname, SET_MAX_NICKNAME_SIZE } },
|
||||
);
|
||||
}
|
||||
|
||||
Result setsysSetDeviceNickname(const char* nickname) {
|
||||
char send_nickname[SET_MAX_NICKNAME_SIZE] = {0};
|
||||
strncpy(send_nickname, nickname, SET_MAX_NICKNAME_SIZE-1);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, send_nickname, SET_MAX_NICKNAME_SIZE, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 78;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_setsysSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatch(&g_setsysSrv, 78,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||
.buffers = { { send_nickname, SET_MAX_NICKNAME_SIZE } },
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
// Copyright 2017 plutoo
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_smSrv;
|
||||
static u64 g_refCnt;
|
||||
|
||||
#define MAX_OVERRIDES 32
|
||||
|
||||
@ -33,28 +29,17 @@ void smAddOverrideHandle(u64 name, Handle handle)
|
||||
|
||||
Handle smGetServiceOverride(u64 name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<g_smOverridesNum; i++)
|
||||
{
|
||||
for (size_t i = 0; i < g_smOverridesNum; i++)
|
||||
if (g_smOverrides[i].name == name)
|
||||
return g_smOverrides[i].handle;
|
||||
}
|
||||
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
bool smHasInitialized(void) {
|
||||
return serviceIsActive(&g_smSrv);
|
||||
}
|
||||
NX_GENERATE_SERVICE_GUARD(sm);
|
||||
|
||||
Result smInitialize(void)
|
||||
Result _smInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (smHasInitialized())
|
||||
return 0;
|
||||
|
||||
Handle sm_handle;
|
||||
Result rc = svcConnectToNamedPort(&sm_handle, "sm:");
|
||||
while (R_VALUE(rc) == KERNELRESULT(NotFound)) {
|
||||
@ -68,51 +53,19 @@ Result smInitialize(void)
|
||||
|
||||
Handle tmp;
|
||||
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcSendPid(&c);
|
||||
const struct {
|
||||
u64 pid_placeholder;
|
||||
} in = { 0 };
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 zero;
|
||||
u64 reserved[2];
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->zero = 0;
|
||||
|
||||
rc = serviceIpcDispatch(&g_smSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
||||
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
}
|
||||
rc = serviceDispatchIn(&g_smSrv, 0, in, .in_send_pid = true);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc))
|
||||
smExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void smExit(void)
|
||||
void _smCleanup(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
{
|
||||
serviceClose(&g_smSrv);
|
||||
}
|
||||
serviceClose(&g_smSrv);
|
||||
}
|
||||
|
||||
Service *smGetServiceSession(void)
|
||||
@ -120,43 +73,21 @@ Service *smGetServiceSession(void)
|
||||
return &g_smSrv;
|
||||
}
|
||||
|
||||
u64 smEncodeName(const char* name)
|
||||
{
|
||||
u64 name_encoded = 0;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if (name[i] == '\0')
|
||||
break;
|
||||
|
||||
name_encoded |= ((u64) name[i]) << (8*i);
|
||||
}
|
||||
|
||||
return name_encoded;
|
||||
}
|
||||
|
||||
Result smGetService(Service* service_out, const char* name)
|
||||
{
|
||||
u64 name_encoded = smEncodeName(name);
|
||||
Handle handle = smGetServiceOverride(name_encoded);
|
||||
Result rc;
|
||||
bool own_handle = false;
|
||||
Result rc = 0;
|
||||
|
||||
if (handle != INVALID_HANDLE)
|
||||
{
|
||||
service_out->type = ServiceType_Override;
|
||||
service_out->handle = handle;
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handle == INVALID_HANDLE) {
|
||||
own_handle = true;
|
||||
rc = smGetServiceOriginal(&handle, name_encoded);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
service_out->type = ServiceType_Normal;
|
||||
service_out->handle = handle;
|
||||
}
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(service_out, handle);
|
||||
service_out->own_handle = own_handle;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -164,117 +95,35 @@ Result smGetService(Service* service_out, const char* name)
|
||||
|
||||
Result smGetServiceOriginal(Handle* handle_out, u64 name)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
const struct {
|
||||
u64 service_name;
|
||||
u64 reserved[2];
|
||||
} *raw;
|
||||
} in = { name };
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->service_name = name;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
||||
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_smSrv, 1, in,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
|
||||
.out_handles = handle_out,
|
||||
);
|
||||
}
|
||||
|
||||
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions)
|
||||
{
|
||||
const struct {
|
||||
u64 service_name;
|
||||
u32 is_light;
|
||||
u32 max_sessions;
|
||||
} *raw;
|
||||
} in = { smEncodeName(name), !!is_light, max_sessions };
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->service_name = smEncodeName(name);
|
||||
raw->is_light = !!is_light;
|
||||
raw->max_sessions = max_sessions;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
||||
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_smSrv, 2, in,
|
||||
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
|
||||
.out_handles = handle_out,
|
||||
);
|
||||
}
|
||||
|
||||
Result smUnregisterService(const char* name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
Result smUnregisterService(const char* name)
|
||||
{
|
||||
const struct {
|
||||
u64 service_name;
|
||||
u64 reserved;
|
||||
} *raw;
|
||||
} in = { smEncodeName(name) };
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
raw->service_name = smEncodeName(name);
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
||||
|
||||
resp = r.Raw;
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_smSrv, 3, in);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,28 +1,19 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "services/time.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_timeSrv;
|
||||
static Service g_timeUserSystemClock;
|
||||
static Service g_timeNetworkSystemClock;
|
||||
static Service g_timeTimeZoneService;
|
||||
static Service g_timeLocalSystemClock;
|
||||
static u64 g_refCnt;
|
||||
|
||||
static Result _timeGetSession(Service* srv_out, u64 cmd_id);
|
||||
static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
|
||||
|
||||
Result timeInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
NX_GENERATE_SERVICE_GUARD(time);
|
||||
|
||||
if (serviceIsActive(&g_timeSrv))
|
||||
return 0;
|
||||
|
||||
Result rc;
|
||||
Result _timeInitialize(void) {
|
||||
Result rc=0;
|
||||
|
||||
rc = smGetService(&g_timeSrv, "time:s");
|
||||
if (R_FAILED(rc))
|
||||
@ -31,75 +22,33 @@ Result timeInitialize(void)
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
rc = _timeGetSession(&g_timeUserSystemClock, 0);
|
||||
rc = _timeCmdGetSession(&g_timeSrv, &g_timeUserSystemClock, 0);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeNetworkSystemClock, 1);
|
||||
rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeTimeZoneService, 3);
|
||||
rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeLocalSystemClock, 4);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
timeExit();
|
||||
rc = _timeCmdGetSession(&g_timeSrv, &g_timeLocalSystemClock, 4);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void timeExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
{
|
||||
serviceClose(&g_timeLocalSystemClock);
|
||||
serviceClose(&g_timeTimeZoneService);
|
||||
serviceClose(&g_timeNetworkSystemClock);
|
||||
serviceClose(&g_timeUserSystemClock);
|
||||
serviceClose(&g_timeSrv);
|
||||
}
|
||||
void _timeCleanup(void) {
|
||||
serviceClose(&g_timeLocalSystemClock);
|
||||
serviceClose(&g_timeTimeZoneService);
|
||||
serviceClose(&g_timeNetworkSystemClock);
|
||||
serviceClose(&g_timeUserSystemClock);
|
||||
serviceClose(&g_timeSrv);
|
||||
}
|
||||
|
||||
Service* timeGetServiceSession(void) {
|
||||
return &g_timeSrv;
|
||||
}
|
||||
|
||||
static Result _timeGetSession(Service* srv_out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(srv_out, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Service* _timeGetClockSession(TimeType type) {
|
||||
Service* timeGetServiceSession_SystemClock(TimeType type) {
|
||||
if (type==TimeType_UserSystemClock) {
|
||||
return &g_timeUserSystemClock;
|
||||
}
|
||||
@ -114,403 +63,143 @@ static Service* _timeGetClockSession(TimeType type) {
|
||||
}
|
||||
}
|
||||
|
||||
Service* timeGetServiceSession_TimeZoneService(void) {
|
||||
return &g_timeTimeZoneService;
|
||||
}
|
||||
|
||||
static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
|
||||
return serviceDispatch(srv, cmd_id,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = srv_out,
|
||||
);
|
||||
}
|
||||
|
||||
static Result _timeCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
|
||||
return serviceDispatchIn(srv, cmd_id, inval);
|
||||
}
|
||||
|
||||
static Result _timeCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _appletCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
Result timeGetCurrentTime(TimeType type, u64 *timestamp) {
|
||||
Service *srv = _timeGetClockSession(type);
|
||||
Service *srv = timeGetServiceSession_SystemClock(type);
|
||||
|
||||
if (srv==NULL)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 timestamp;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && timestamp) *timestamp = resp->timestamp;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _timeCmdNoInOutU64(srv, timestamp, 0);
|
||||
}
|
||||
|
||||
Result timeSetCurrentTime(TimeType type, u64 timestamp) {
|
||||
Service *srv = _timeGetClockSession(type);
|
||||
Service *srv = timeGetServiceSession_SystemClock(type);
|
||||
|
||||
if (srv==NULL)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 timestamp;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->timestamp = timestamp;
|
||||
|
||||
Result rc = serviceIpcDispatch(srv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _timeCmdInU64NoOut(srv, timestamp, 1);
|
||||
}
|
||||
|
||||
Result timeGetDeviceLocationName(TimeLocationName *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
TimeLocationName name;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && name) memcpy(name, &resp->name, sizeof(TimeLocationName));
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchOut(&g_timeTimeZoneService, 0, *name);
|
||||
}
|
||||
|
||||
Result timeSetDeviceLocationName(const TimeLocationName *name) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
TimeLocationName name;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
memcpy(&raw->name, name, sizeof(TimeLocationName));
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_timeTimeZoneService, 1, *name);
|
||||
}
|
||||
|
||||
Result timeGetTotalLocationNameCount(u32 *total_location_name_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
Result timeGetTotalLocationNameCount(s32 *total_location_name_count) {
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 total_location_name_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && total_location_name_count) *total_location_name_count = resp->total_location_name_count;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _appletCmdNoInOutU32(&g_timeTimeZoneService, (u32*)total_location_name_count, 2);
|
||||
}
|
||||
|
||||
Result timeLoadLocationNameList(u32 index, TimeLocationName *location_name_array, size_t location_name_size, u32 *location_name_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, location_name_array, location_name_size, BufferType_Normal);
|
||||
Result timeLoadLocationNameList(s32 index, TimeLocationName *location_name_array, s32 location_name_max, s32 *location_name_count) {
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 index;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
raw->index = index;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 location_name_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && location_name_count) *location_name_count = resp->location_name_count;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(&g_timeTimeZoneService, 3, index, *location_name_count,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { location_name_array, sizeof(TimeLocationName)*location_name_max } },
|
||||
);
|
||||
}
|
||||
|
||||
Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
TimeLocationName name;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
memcpy(&raw->name, name, sizeof(TimeLocationName));
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchIn(&g_timeTimeZoneService, 4, *name,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { rule, sizeof(TimeZoneRule) } },
|
||||
);
|
||||
}
|
||||
|
||||
Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 timestamp;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 100;
|
||||
raw->timestamp = timestamp;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
TimeCalendarTime caltime;
|
||||
TimeCalendarAdditionalInfo info;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && caltime) memcpy(caltime, &resp->caltime, sizeof(TimeCalendarTime));
|
||||
if (R_SUCCEEDED(rc) && info) memcpy(info, &resp->info, sizeof(TimeCalendarAdditionalInfo));
|
||||
}
|
||||
TimeCalendarTime caltime;
|
||||
TimeCalendarAdditionalInfo info;
|
||||
} out;
|
||||
|
||||
Result rc = serviceDispatchInOut(&g_timeTimeZoneService, 100, timestamp, out,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||
.buffers = { { rule, sizeof(TimeZoneRule) } },
|
||||
);
|
||||
if (R_SUCCEEDED(rc) && caltime) *caltime = out.caltime;
|
||||
if (R_SUCCEEDED(rc) && info) *info = out.info;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 timestamp;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 101;
|
||||
raw->timestamp = timestamp;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
TimeCalendarTime caltime;
|
||||
TimeCalendarAdditionalInfo info;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && caltime) memcpy(caltime, &resp->caltime, sizeof(TimeCalendarTime));
|
||||
if (R_SUCCEEDED(rc) && info) memcpy(info, &resp->info, sizeof(TimeCalendarAdditionalInfo));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
|
||||
ipcAddRecvStatic(&c, timestamp_list, timestamp_list_size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
TimeCalendarTime caltime;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 201;
|
||||
raw->caltime = *caltime;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 timestamp_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && timestamp_count) *timestamp_count = resp->timestamp_count;
|
||||
}
|
||||
TimeCalendarAdditionalInfo info;
|
||||
} out;
|
||||
|
||||
Result rc = serviceDispatchInOut(&g_timeTimeZoneService, 101, timestamp, out);
|
||||
if (R_SUCCEEDED(rc) && caltime) *caltime = out.caltime;
|
||||
if (R_SUCCEEDED(rc) && info) *info = out.info;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvStatic(&c, timestamp_list, timestamp_list_size, 0);
|
||||
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count) {
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
TimeCalendarTime caltime;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 202;
|
||||
raw->caltime = *caltime;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 timestamp_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && timestamp_count) *timestamp_count = resp->timestamp_count;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return serviceDispatchInOut(&g_timeTimeZoneService, 201, *caltime, *timestamp_count,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcPointer | SfBufferAttr_Out,
|
||||
},
|
||||
.buffers = {
|
||||
{ rule, sizeof(TimeZoneRule) },
|
||||
{ timestamp_list, sizeof(u64)*timestamp_list_count },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count) {
|
||||
if (!serviceIsActive(&g_timeTimeZoneService))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return serviceDispatchInOut(&g_timeTimeZoneService, 202, *caltime, *timestamp_count,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { timestamp_list, sizeof(u64)*timestamp_list_count } },
|
||||
);
|
||||
}
|
||||
|
||||
48
nx/source/services/ts.c
Normal file
48
nx/source/services/ts.c
Normal file
@ -0,0 +1,48 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
#include "service_guard.h"
|
||||
#include "runtime/hosversion.h"
|
||||
#include "services/ts.h"
|
||||
|
||||
static Service g_tsSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(ts);
|
||||
|
||||
Result _tsInitialize(void) {
|
||||
return smGetService(&g_tsSrv, "ts");
|
||||
}
|
||||
|
||||
void _tsCleanup(void) {
|
||||
serviceClose(&g_tsSrv);
|
||||
}
|
||||
|
||||
Service* tsGetServiceSession(void) {
|
||||
return &g_tsSrv;
|
||||
}
|
||||
|
||||
static Result _tsCmdInU8Out32(u8 inval, u32 *out, u64 cmd_id) {
|
||||
return serviceDispatchInOut(&g_tsSrv, cmd_id, inval, *out);
|
||||
}
|
||||
|
||||
Result tsGetTemperatureRange(TsLocation location, s32 *min_temperature, s32 *max_temperature) {
|
||||
u8 tmp_location = location;
|
||||
|
||||
struct {
|
||||
s32 min_temperature;
|
||||
s32 max_temperature;
|
||||
} out;
|
||||
|
||||
Result rc = serviceDispatchInOut(&g_tsSrv, 0, tmp_location, out);
|
||||
if (R_SUCCEEDED(rc) && min_temperature) *min_temperature = out.min_temperature;
|
||||
if (R_SUCCEEDED(rc) && max_temperature) *max_temperature = out.max_temperature;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result tsGetTemperature(TsLocation location, s32 *temperature) {
|
||||
return _tsCmdInU8Out32(location, (u32*)temperature, 1);
|
||||
}
|
||||
|
||||
Result tsGetTemperatureMilliC(TsLocation location, s32 *temperature) {
|
||||
return _tsCmdInU8Out32(location, (u32*)temperature, 3);
|
||||
}
|
||||
|
||||
@ -725,8 +725,6 @@ Result usbHsIfOpenUsbEp(UsbHsClientIfSession* s, UsbHsClientEpSession* ep, u16 m
|
||||
if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2);
|
||||
}
|
||||
|
||||
if (hosversionAtLeast(3,0,0) && R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(ep->s.handle, &ep->ptrbufsize);
|
||||
|
||||
if (R_FAILED(rc)) {
|
||||
serviceClose(&ep->s);
|
||||
eventClose(&ep->eventXfer);
|
||||
@ -854,7 +852,7 @@ static Result _usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* re
|
||||
ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal);
|
||||
}
|
||||
else {
|
||||
ipcAddRecvSmart(&c, s->ptrbufsize, reports, sizeof(UsbHsXferReport) * max_reports, 0);
|
||||
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, reports, sizeof(UsbHsXferReport) * max_reports, 0);
|
||||
}
|
||||
|
||||
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
||||
|
||||
@ -1,111 +1,34 @@
|
||||
/**
|
||||
* @file wlaninf.c
|
||||
* @brief WLAN InfraManager service IPC wrapper.
|
||||
* @author natinusala
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "services/sm.h"
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include "service_guard.h"
|
||||
#include "services/wlaninf.h"
|
||||
#include "arm/atomics.h"
|
||||
|
||||
static Service g_wlaninfSrv;
|
||||
static u64 g_refCnt;
|
||||
|
||||
Result wlaninfInitialize(void) {
|
||||
Result rc;
|
||||
NX_GENERATE_SERVICE_GUARD(wlaninf);
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_wlaninfSrv))
|
||||
return 0;
|
||||
|
||||
rc = smGetService(&g_wlaninfSrv, "wlan:inf");
|
||||
|
||||
if (R_FAILED(rc))
|
||||
wlaninfExit();
|
||||
|
||||
return rc;
|
||||
Result _wlaninfInitialize(void) {
|
||||
return smGetService(&g_wlaninfSrv, "wlan:inf");
|
||||
}
|
||||
|
||||
void wlaninfExit(void) {
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
serviceClose(&g_wlaninfSrv);
|
||||
}
|
||||
void _wlaninfCleanup(void) {
|
||||
serviceClose(&g_wlaninfSrv);
|
||||
}
|
||||
|
||||
Service* wlaninfGetServiceSession(void) {
|
||||
return &g_wlaninfSrv;
|
||||
}
|
||||
|
||||
static Result _wlaninfCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
Result wlaninfGetState(WlanInfState* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_wlaninfSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 10;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_wlaninfSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_wlaninfSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
*out = resp->out;
|
||||
}
|
||||
|
||||
u32 tmp=0;
|
||||
Result rc = _wlaninfCmdNoInOutU32(&g_wlaninfSrv, &tmp, 10);
|
||||
if (R_SUCCEEDED(rc) && out) *out = tmp;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result wlaninfGetRSSI(s32* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_wlaninfSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_wlaninfSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
s32 out;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_wlaninfSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
*out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return _wlaninfCmdNoInOutU32(&g_wlaninfSrv, (u32*)out, 12);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user